/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │ ╞══════════════════════════════════════════════════════════════════════════════╡ │ Copyright 2020 Justine Alexandra Roberts Tunney │ │ │ │ Permission to use, copy, modify, and/or distribute this software for │ │ any purpose with or without fee is hereby granted, provided that the │ │ above copyright notice and this permission notice appear in all copies. │ │ │ │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.h" #include "libc/calls/struct/stat.h" #include "libc/elf/def.h" #include "libc/fmt/conv.h" #include "libc/intrin/bsr.h" #include "libc/intrin/popcnt.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/macros.h" #include "libc/mem/mem.h" #include "libc/nexgen32e/crc32.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/str/tab.h" #include "libc/sysv/consts/o.h" #include "libc/sysv/consts/s.h" #include "libc/x/x.h" #include "libc/x/xasprintf.h" #include "third_party/chibicc/file.h" #include "third_party/gdtoa/gdtoa.h" #include "libc/serialize.h" #include "libc/ctype.h" #include "tool/build/lib/elfwriter.h" #define OSZ 0x66 #define ASZ 0x67 #define REX 0x40 // byte #define REXB 0x41 // src #define REXX 0x42 // index #define REXR 0x44 // dest #define REXW 0x48 // quad #define HASASZ 0x00010000 #define HASBASE 0x00020000 #define HASINDEX 0x00040000 #define ISRIP 0x00080000 #define ISREG 0x00100000 #define APPEND(L) \ if (++L.n > L.c) { \ L.c = L.n + 2 + (L.c >> 1); \ L.p = realloc(L.p, L.c * sizeof(*L.p)); \ } #define IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1)) #define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) #define READ128BE(S) ((uint128_t)READ64BE(S) << 64 | READ64BE((S) + 8)) struct As { int i; // things int section; // sections int previous; // sections int inpath; // strings int outpath; // strings int counter; int pcrelative; bool inhibiterr; bool inhibitwarn; struct Ints { unsigned long n, c; int128_t *p; } ints; struct Floats { unsigned long n, c; long double *p; } floats; struct Slices { unsigned long n, c; struct Slice { unsigned long n, c; char *p; } * p; } slices; struct Sauces { unsigned long n, c; struct Sauce { unsigned path; // strings unsigned line; // 1-indexed } * p; } sauces; struct Things { unsigned long n, c; struct Thing { enum ThingType { TT_INT, TT_FLOAT, TT_SLICE, TT_PUNCT, TT_FORWARD, TT_BACKWARD, } t : 4; unsigned s : 28; // sauces unsigned i; // identity,ints,floats,slices } * p; } things; struct Sections { unsigned long n, c; struct Section { unsigned name; // strings int flags; int type; int align; struct Slice binary; } * p; } sections; struct Symbols { unsigned long n, c; struct Symbol { bool isused; unsigned char stb; // STB_* unsigned char stv; // STV_* unsigned char type; // STT_* unsigned name; // slices unsigned section; // sections long offset; long size; struct ElfWriterSymRef ref; } * p; } symbols; struct HashTable { unsigned i, n; struct HashEntry { unsigned h; unsigned i; } * p; } symbolindex; struct Labels { unsigned long n, c; struct Label { unsigned id; unsigned tok; // things unsigned symbol; // symbols } * p; } labels; struct Relas { unsigned long n, c; struct Rela { bool isdead; int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} unsigned expr; // exprs unsigned section; // sections long offset; long addend; } * p; } relas; struct Exprs { unsigned long n, c; struct Expr { enum ExprKind { EX_INT, // integer EX_SYM, // things (then symbols after eval) EX_NEG, // unary - EX_NOT, // unary ! EX_BITNOT, // unary ~ EX_ADD, // + EX_SUB, // - EX_MUL, // * EX_DIV, // / EX_REM, // % EX_AND, // & EX_OR, // | EX_XOR, // ^ EX_SHL, // << EX_SHR, // >> EX_EQ, // == EX_NE, // != EX_LT, // < EX_LE, // <= } kind; enum ExprMod { EM_NORMAL, EM_GOTPCREL, EM_DTPOFF, EM_TPOFF, } em; unsigned tok; int lhs; int rhs; int128_t x; bool isvisited; bool isevaluated; } * p; } exprs; struct Strings { unsigned long n, c; char **p; } strings, incpaths; struct SectionStack { unsigned long n, c; int *p; } sectionstack; }; static const char kPrefixByte[30] = { 0x67, 0x2E, 0x66, 0x3E, 0x26, 0x64, 0x65, 0xF0, 0xF3, 0xF3, 0xF2, 0xF2, 0xF3, 0x40, 0x41, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4C, 0x4D, 0x4E, 0x4F, 0x4A, 0x4B, 0x42, 0x43, 0x36, }; static const char kPrefix[30][8] = { "addr32", "cs", "data16", "ds", "es", "fs", "gs", "lock", "rep", "repe", "repne", "repnz", "repz", "rex", "rex.b", "rex.r", "rex.rb", "rex.rx", "rex.rxb", "rex.w", "rex.wb", "rex.wr", "rex.wrb", "rex.wrx", "rex.wrxb", "rex.wx", "rex.wxb", "rex.x", "rex.xb", "ss", }; static const char kSegmentByte[6] = {0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36}; static const char kSegment[6][2] = {"cs", "ds", "es", "fs", "gs", "ss"}; /** * Context-sensitive register encoding information. * * ┌rex * │ ┌log₂size * │ │ ┌reg * ├──────┐ ├─┐├─┐ * 0b0000000000000000 */ static const struct Reg { char s[8]; short reg; short rm; short base; short index; } kRegs[] = /* clang-format off */ { {"ah", 4, 4, -1, -1 }, {"al", 0, 0, -1, -1 }, {"ax", 0 | 1<<3, 0 | 1<<3, -1, -1 }, {"bh", 7, 7, -1, -1 }, {"bl", 3, 3, -1, -1 }, {"bp", 5 | 1<<3, 5 | 1<<3, -1, -1 }, {"bpl", 5 | REX<<8, 5 | REX<<8, -1, -1 }, {"bx", 3 | 1<<3, 3 | 1<<3, -1, -1 }, {"ch", 5, 5, -1, -1 }, {"cl", 1, 1, -1, -1 }, {"cx", 1 | 1<<3, 1 | 1<<3, -1, -1 }, {"dh", 6, 6, -1, -1 }, {"di", 7 | 1<<3, 7 | 1<<3, -1, -1 }, {"dil", 7 | REX<<8, 7 | REX<<8, -1, -1 }, {"dl", 2, 2, -1, -1 }, {"dx", 2 | 1<<3, 2 | 1<<3, -1, -1 }, {"eax", 0 | 2<<3, 0 | 2<<3, 0 | 2<<3, 0 | 2<<3 }, {"ebp", 5 | 2<<3, 5 | 2<<3, 5 | 2<<3, 5 | 2<<3 }, {"ebx", 3 | 2<<3, 3 | 2<<3, 3 | 2<<3, 3 | 2<<3 }, {"ecx", 1 | 2<<3, 1 | 2<<3, 1 | 2<<3, 1 | 2<<3 }, {"edi", 7 | 2<<3, 7 | 2<<3, 7 | 2<<3, 7 | 2<<3 }, {"edx", 2 | 2<<3, 2 | 2<<3, 2 | 2<<3, 2 | 2<<3 }, {"eiz", -1, -1, -1, 4 | 2<<3 }, {"esi", 6 | 2<<3, 6 | 2<<3, 6 | 2<<3, 6 | 2<<3 }, {"esp", 4 | 2<<3, 4 | 2<<3, 4 | 2<<3, 4 | 2<<3 }, {"mm0", 0 | 3<<3, 0 | 3<<3, -1, -1 }, {"mm1", 1 | 3<<3, 1 | 3<<3, -1, -1 }, {"mm2", 2 | 3<<3, 2 | 3<<3, -1, -1 }, {"mm3", 3 | 3<<3, 3 | 3<<3, -1, -1 }, {"mm4", 4 | 3<<3, 4 | 3<<3, -1, -1 }, {"mm5", 5 | 3<<3, 5 | 3<<3, -1, -1 }, {"mm6", 6 | 3<<3, 6 | 3<<3, -1, -1 }, {"mm7", 7 | 3<<3, 7 | 3<<3, -1, -1 }, {"mm8", 0 | 3<<3 | REXR<<8, 0 | 3<<3 | REXB<<8, -1, -1 }, {"mm9", 1 | 3<<3 | REXR<<8, 1 | 3<<3 | REXB<<8, -1, -1 }, {"r10", 2 | 3<<3 | REXR<<8 | REXW<<8, 2 | 3<<3 | REXB<<8 | REXW<<8, 2 | 3<<3 | REXB<<8, 2 | 3<<3 | REXX<<8 }, {"r10b", 2 | REXR<<8, 2 | REXB<<8, -1, -1 }, {"r10d", 2 | 2<<3 | REXR<<8, 2 | 2<<3 | REXB<<8, 2 | 2<<3 | REXB<<8, 2 | 2<<3 | REXX<<8 }, {"r10w", 2 | 1<<3 | REXR<<8, 2 | 1<<3 | REXB<<8, -1, -1 }, {"r11", 3 | 3<<3 | REXR<<8 | REXW<<8, 3 | 3<<3 | REXB<<8 | REXW<<8, 3 | 3<<3 | REXB<<8, 3 | 3<<3 | REXX<<8 }, {"r11b", 3 | REXR<<8, 3 | REXB<<8, -1, -1 }, {"r11d", 3 | 2<<3 | REXR<<8, 3 | 2<<3 | REXB<<8, 3 | 2<<3 | REXB<<8, 3 | 2<<3 | REXX<<8 }, {"r11w", 3 | 1<<3 | REXR<<8, 3 | 1<<3 | REXB<<8, -1, -1 }, {"r12", 4 | 3<<3 | REXR<<8 | REXW<<8, 4 | 3<<3 | REXB<<8 | REXW<<8, 4 | 3<<3 | REXB<<8, 4 | 3<<3 | REXX<<8 }, {"r12b", 4 | REXR<<8, 4 | REXB<<8, -1, -1 }, {"r12d", 4 | 2<<3 | REXR<<8, 4 | 2<<3 | REXB<<8, 4 | 2<<3 | REXB<<8, 4 | 2<<3 | REXX<<8 }, {"r12w", 4 | 1<<3 | REXR<<8, 4 | 1<<3 | REXB<<8, -1, -1 }, {"r13", 5 | 3<<3 | REXR<<8 | REXW<<8, 5 | 3<<3 | REXB<<8 | REXW<<8, 5 | 3<<3 | REXB<<8, 5 | 3<<3 | REXX<<8 }, {"r13b", 5 | REXR<<8, 5 | REXB<<8, -1, -1 }, {"r13d", 5 | 2<<3 | REXR<<8, 5 | 2<<3 | REXB<<8, 5 | 2<<3 | REXB<<8, 5 | 2<<3 | REXX<<8 }, {"r13w", 5 | 1<<3 | REXR<<8, 5 | 1<<3 | REXB<<8, -1, -1 }, {"r14", 6 | 3<<3 | REXR<<8 | REXW<<8, 6 | 3<<3 | REXB<<8 | REXW<<8, 6 | 3<<3 | REXB<<8, 6 | 3<<3 | REXX<<8 }, {"r14b", 6 | REXR<<8, 6 | REXB<<8, -1, -1 }, {"r14d", 6 | 2<<3 | REXR<<8, 6 | 2<<3 | REXB<<8, 6 | 2<<3 | REXB<<8, 6 | 2<<3 | REXX<<8 }, {"r14w", 6 | 1<<3 | REXR<<8, 6 | 1<<3 | REXB<<8, -1, -1 }, {"r15", 7 | 3<<3 | REXR<<8 | REXW<<8, 7 | 3<<3 | REXB<<8 | REXW<<8, 7 | 3<<3 | REXB<<8, 7 | 3<<3 | REXX<<8 }, {"r15b", 7 | REXR<<8, 7 | REXB<<8, -1, -1 }, {"r15d", 7 | 2<<3 | REXR<<8, 7 | 2<<3 | REXB<<8, 7 | 2<<3 | REXB<<8, 7 | 2<<3 | REXX<<8 }, {"r15w", 7 | 1<<3 | REXR<<8, 7 | 1<<3 | REXB<<8, -1, -1 }, {"r8", 0 | 3<<3 | REXR<<8 | REXW<<8, 0 | 3<<3 | REXB<<8 | REXW<<8, 0 | 3<<3 | REXB<<8, 0 | 3<<3 | REXX<<8 }, {"r8b", 0 | REXR<<8, 0 | REXB<<8, -1, -1 }, {"r8d", 0 | 2<<3 | REXR<<8, 0 | 2<<3 | REXB<<8, 0 | 2<<3 | REXB<<8, 0 | 2<<3 | REXX<<8 }, {"r8w", 0 | 1<<3 | REXR<<8, 0 | 1<<3 | REXB<<8, -1, -1 }, {"r9", 1 | 3<<3 | REXR<<8 | REXW<<8, 1 | 3<<3 | REXB<<8 | REXW<<8, 1 | 3<<3 | REXB<<8, 1 | 3<<3 | REXX<<8 }, {"r9b", 1 | REXR<<8, 1 | REXB<<8, -1, -1 }, {"r9d", 1 | 2<<3 | REXR<<8, 1 | 2<<3 | REXB<<8, 1 | 2<<3 | REXB<<8, 1 | 2<<3 | REXX<<8 }, {"r9w", 1 | 1<<3 | REXR<<8, 1 | 1<<3 | REXB<<8, -1, -1 }, {"rax", 0 | 3<<3 | REXW<<8, 0 | 3<<3 | REXW<<8, 0 | 3<<3, 0 | 3<<3 }, {"rbp", 5 | 3<<3 | REXW<<8, 5 | 3<<3 | REXW<<8, 5 | 3<<3, 5 | 3<<3 }, {"rbx", 3 | 3<<3 | REXW<<8, 3 | 3<<3 | REXW<<8, 3 | 3<<3, 3 | 3<<3 }, {"rcx", 1 | 3<<3 | REXW<<8, 1 | 3<<3 | REXW<<8, 1 | 3<<3, 1 | 3<<3 }, {"rdi", 7 | 3<<3 | REXW<<8, 7 | 3<<3 | REXW<<8, 7 | 3<<3, 7 | 3<<3 }, {"rdx", 2 | 3<<3 | REXW<<8, 2 | 3<<3 | REXW<<8, 2 | 3<<3, 2 | 3<<3 }, {"riz", -1, -1, -1, 4 | 3<<3 }, {"rsi", 6 | 3<<3 | REXW<<8, 6 | 3<<3 | REXW<<8, 6 | 3<<3, 6 | 3<<3 }, {"rsp", 4 | 3<<3 | REXW<<8, 4 | 3<<3 | REXW<<8, 4 | 3<<3, 4 | 3<<3 }, {"si", 6 | 1<<3, 6 | 1<<3, 6 | 1<<3, 6 | 1<<3 }, {"sil", 6 | REX<<8, 6 | REX<<8, 6 | REX<<8, 6 | REX<<8 }, {"sp", 4 | 1<<3, 4 | 1<<3, 4 | 1<<3, 4 | 1<<3 }, {"spl", 4 | REX<<8, 4 | REX<<8, 4 | REX<<8, 4 | REX<<8 }, {"st", 0 | 4<<3, 0 | 4<<3, -1, -1 }, {"st(0)", 0 | 4<<3, 0 | 4<<3, -1, -1 }, {"st(1)", 1 | 4<<3, 1 | 4<<3, -1, -1 }, {"st(2)", 2 | 4<<3, 2 | 4<<3, -1, -1 }, {"st(3)", 3 | 4<<3, 3 | 4<<3, -1, -1 }, {"st(4)", 4 | 4<<3, 4 | 4<<3, -1, -1 }, {"st(5)", 5 | 4<<3, 5 | 4<<3, -1, -1 }, {"st(6)", 6 | 4<<3, 6 | 4<<3, -1, -1 }, {"st(7)", 7 | 4<<3, 7 | 4<<3, -1, -1 }, {"xmm0", 0 | 4<<3, 0 | 4<<3, -1, -1 }, {"xmm1", 1 | 4<<3, 1 | 4<<3, -1, -1 }, {"xmm10", 2 | 4<<3 | REXR<<8, 2 | 4<<3 | REXB<<8, -1, -1 }, {"xmm11", 3 | 4<<3 | REXR<<8, 3 | 4<<3 | REXB<<8, -1, -1 }, {"xmm12", 4 | 4<<3 | REXR<<8, 4 | 4<<3 | REXB<<8, -1, -1 }, {"xmm13", 5 | 4<<3 | REXR<<8, 5 | 4<<3 | REXB<<8, -1, -1 }, {"xmm14", 6 | 4<<3 | REXR<<8, 6 | 4<<3 | REXB<<8, -1, -1 }, {"xmm15", 7 | 4<<3 | REXR<<8, 7 | 4<<3 | REXB<<8, -1, -1 }, {"xmm2", 2 | 4<<3, 2 | 4<<3, -1, -1 }, {"xmm3", 3 | 4<<3, 3 | 4<<3, -1, -1 }, {"xmm4", 4 | 4<<3, 4 | 4<<3, -1, -1 }, {"xmm5", 5 | 4<<3, 5 | 4<<3, -1, -1 }, {"xmm6", 6 | 4<<3, 6 | 4<<3, -1, -1 }, {"xmm7", 7 | 4<<3, 7 | 4<<3, -1, -1 }, {"xmm8", 0 | 4<<3 | REXR<<8, 0 | 4<<3 | REXB<<8, -1, -1 }, {"xmm9", 1 | 4<<3 | REXR<<8, 1 | 4<<3 | REXB<<8, -1, -1 }, } /* clang-format on */; long as_hashmap_hits; long as_hashmap_miss; static bool IsPunctMergeable(int c) { switch (c) { case ',': case ';': case '$': return false; default: return true; } } static char *PunctToStr(int p, char b[4]) { int c, i, j; bzero(b, 4); for (j = 0, i = 2; i >= 0; --i) { if ((c = (p >> (i * 8)) & 0xff)) { b[j++] = c; } } return b; } static void PrintSlice(struct Slice s) { fprintf(stderr, "%.*s\n", s.n, s.p); } static char *SaveString(struct Strings *l, char *p) { APPEND((*l)); l->p[l->n - 1] = p; return p; } static int StrDup(struct As *a, const char *s) { SaveString(&a->strings, strdup(s)); return a->strings.n - 1; } static int SliceDup(struct As *a, struct Slice s) { SaveString(&a->strings, strndup(s.p, s.n)); return a->strings.n - 1; } static int AppendSauce(struct As *a, int path, int line) { if (!a->sauces.n || (line != a->sauces.p[a->sauces.n - 1].line || path != a->sauces.p[a->sauces.n - 1].path)) { APPEND(a->sauces); a->sauces.p[a->sauces.n - 1].path = path; a->sauces.p[a->sauces.n - 1].line = line; } return a->sauces.n - 1; } static void AppendExpr(struct As *a) { APPEND(a->exprs); bzero(a->exprs.p + a->exprs.n - 1, sizeof(*a->exprs.p)); a->exprs.p[a->exprs.n - 1].tok = a->i; a->exprs.p[a->exprs.n - 1].lhs = -1; a->exprs.p[a->exprs.n - 1].rhs = -1; } static void AppendThing(struct As *a) { APPEND(a->things); bzero(a->things.p + a->things.n - 1, sizeof(*a->things.p)); } static void AppendRela(struct As *a) { APPEND(a->relas); bzero(a->relas.p + a->relas.n - 1, sizeof(*a->relas.p)); } static void AppendSlice(struct As *a) { APPEND(a->slices); bzero(a->slices.p + a->slices.n - 1, sizeof(*a->slices.p)); } static int AppendSection(struct As *a, int name, int flags, int type) { int i; APPEND(a->sections); i = a->sections.n - 1; CHECK_LT(i, SHN_LORESERVE); a->sections.p[i].name = name; a->sections.p[i].flags = flags; a->sections.p[i].type = type; a->sections.p[i].align = 1; a->sections.p[i].binary.p = NULL; a->sections.p[i].binary.n = 0; return i; } static struct As *NewAssembler(void) { struct As *a = calloc(1, sizeof(struct As)); AppendSlice(a); AppendSection(a, StrDup(a, ""), 0, SHT_NULL); AppendSection(a, StrDup(a, ".text"), SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS); AppendSection(a, StrDup(a, ".data"), SHF_ALLOC | SHF_WRITE, SHT_PROGBITS); AppendSection(a, StrDup(a, ".bss"), SHF_ALLOC | SHF_WRITE, SHT_NOBITS); a->section = 1; return a; } static void FreeAssembler(struct As *a) { int i; for (i = 0; i < a->sections.n; ++i) free(a->sections.p[i].binary.p); for (i = 0; i < a->strings.n; ++i) free(a->strings.p[i]); for (i = 0; i < a->incpaths.n; ++i) free(a->incpaths.p[i]); free(a->ints.p); free(a->floats.p); free(a->slices.p); free(a->sauces.p); free(a->things.p); free(a->sections.p); free(a->symbols.p); free(a->symbolindex.p); free(a->labels.p); free(a->relas.p); free(a->exprs.p); free(a->strings.p); free(a->incpaths.p); free(a->sectionstack.p); free(a); } static void ReadFlags(struct As *a, int argc, char *argv[]) { int i; a->inpath = StrDup(a, "-"); a->outpath = StrDup(a, "a.out"); for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-o")) { a->outpath = StrDup(a, argv[++i]); } else if (startswith(argv[i], "-o")) { a->outpath = StrDup(a, argv[i] + 2); } else if (!strcmp(argv[i], "-I")) { SaveString(&a->incpaths, strdup(argv[++i])); } else if (startswith(argv[i], "-I")) { SaveString(&a->incpaths, strdup(argv[i] + 2)); } else if (!strcmp(argv[i], "-Z")) { a->inhibiterr = true; } else if (!strcmp(argv[i], "-W")) { a->inhibitwarn = true; } else if (argv[i][0] != '-') { a->inpath = StrDup(a, argv[i]); } } } static int ReadCharLiteral(struct Slice *buf, int c, char *p, int *i) { int x; if (c != '\\') return c; switch ((c = p[(*i)++])) { case 'a': return '\a'; case 'b': return '\b'; case 't': return '\t'; case 'n': return '\n'; case 'v': return '\v'; case 'f': return '\f'; case 'r': return '\r'; case 'e': return 033; case 'x': if ((x = kHexToInt[p[*i] & 255]) != -1) { *i += 1, c = x; if ((x = kHexToInt[p[*i] & 255]) != -1) { *i += 1, c = c << 4 | x; } } return c; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c -= '0'; if ('0' <= p[*i] && p[*i] <= '7') { c = c * 8 + (p[(*i)++] - '0'); if ('0' <= p[*i] && p[*i] <= '7') { c = c * 8 + (p[(*i)++] - '0'); } } return c; default: return c; } } static void PrintLocation(struct As *a) { fprintf(stderr, "%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[a->i].s].path], a->sauces.p[a->things.p[a->i].s].line); } static wontreturn void Fail(struct As *a, const char *fmt, ...) { va_list va; PrintLocation(a); va_start(va, fmt); vfprintf(stderr, fmt, va); va_end(va); fputc('\n', stderr); __die(); } static wontreturn void InvalidRegister(struct As *a) { Fail(a, "invalid register"); } static char *FindInclude(struct As *a, const char *file) { int i; char *path; struct stat st; for (i = 0; i < a->incpaths.n; ++i) { path = xjoinpaths(a->incpaths.p[i], file); if (stat(path, &st) != -1 && S_ISREG(st.st_mode)) return path; free(path); } return NULL; } static void Tokenize(struct As *a, int path) { int c, i, line; char *p, *path2; struct Slice buf; bool bol, isfloat, isfpu; if (!fileexists(a->strings.p[path])) { fprintf(stderr, "%s: file not found\n", a->strings.p[path]); exit(1); } p = SaveString(&a->strings, read_file(a->strings.p[path])); p = skip_bom(p); canonicalize_newline(p); remove_backslash_newline(p); line = 1; bol = true; while ((c = *p)) { if (c == '/' && p[1] == '*') { for (i = 2; p[i]; ++i) { if (p[i] == '\n') { ++line; bol = true; } else { bol = false; if (p[i] == '*' && p[i + 1] == '/') { i += 2; break; } } } p += i; continue; } if (c == '#' || (c == '/' && bol) || (c == '/' && p[1] == '/')) { p = strchr(p, '\n'); continue; } if (c == '\n') { AppendThing(a); a->things.p[a->things.n - 1].t = TT_PUNCT; a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); a->things.p[a->things.n - 1].i = ';'; ++p; bol = true; ++line; continue; } bol = false; if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v') { ++p; continue; } if ((c & 0x80) || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_' || c == '%' || c == '@' || (c == '.' && !('0' <= p[1] && p[1] <= '9'))) { isfpu = false; for (i = 1;; ++i) { if (!((p[i] & 0x80) || ('a' <= p[i] && p[i] <= 'z') || ('A' <= p[i] && p[i] <= 'Z') || ('0' <= p[i] && p[i] <= '9') || p[i] == '.' || p[i] == '_' || p[i] == '$' || (isfpu && (p[i] == '(' || p[i] == ')')))) { break; } if (i == 2 && p[i - 2] == '%' && p[i - 1] == 's' && p[i] == 't') { isfpu = true; } } if (i == 4 && !strncasecmp(p, ".end", 4)) break; AppendThing(a); a->things.p[a->things.n - 1].t = TT_SLICE; a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); a->things.p[a->things.n - 1].i = a->slices.n; AppendSlice(a); a->slices.p[a->slices.n - 1].p = p; a->slices.p[a->slices.n - 1].n = i; p += i; continue; } if (('0' <= c && c <= '9') || (c == '.' && '0' <= p[1] && p[1] <= '9')) { isfloat = c == '.'; if (c == '0' && p[1] != '.') { if (p[1] == 'x' || p[1] == 'X') { for (i = 2;; ++i) { if (!(('0' <= p[i] && p[i] <= '9') || ('a' <= p[i] && p[i] <= 'f') || ('A' <= p[i] && p[i] <= 'F'))) { break; } } } else if ((p[1] == 'b' || p[1] == 'B') && ('0' <= p[2] && p[2] <= '9')) { for (i = 2;; ++i) { if (!(p[i] == '0' || p[i] == '1')) break; } } else { for (i = 1;; ++i) { if (!('0' <= p[i] && p[i] <= '7')) break; } } } else { for (i = 1;; ++i) { if (('0' <= p[i] && p[i] <= '9') || p[i] == '-' || p[i] == '+') { continue; } else if (p[i] == '.' || p[i] == 'e' || p[i] == 'E' || p[i] == 'e') { isfloat = true; continue; } break; } } AppendThing(a); if (isfloat) { APPEND(a->floats); a->floats.p[a->floats.n - 1] = strtold(p, NULL); a->things.p[a->things.n - 1].i = a->floats.n - 1; a->things.p[a->things.n - 1].t = TT_FLOAT; } else { APPEND(a->ints); a->ints.p[a->ints.n - 1] = strtoumax(p, NULL, 0); a->things.p[a->things.n - 1].i = a->ints.n - 1; if (p[i] == 'f' || p[i] == 'F') { a->things.p[a->things.n - 1].t = TT_FORWARD; ++i; } else if (p[i] == 'b' || p[i] == 'B') { a->things.p[a->things.n - 1].t = TT_BACKWARD; ++i; } else { a->things.p[a->things.n - 1].t = TT_INT; } } a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); p += i; continue; } if (c == '\'') { i = 1; c = p[i++]; c = ReadCharLiteral(&buf, c, p, &i); if (p[i] == '\'') ++i; p += i; AppendThing(a); a->things.p[a->things.n - 1].t = TT_INT; a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); a->things.p[a->things.n - 1].i = a->ints.n; APPEND(a->ints); a->ints.p[a->ints.n - 1] = c; continue; } if (c == '"') { bzero(&buf, sizeof(buf)); for (i = 1; (c = p[i++]);) { if (c == '"') break; c = ReadCharLiteral(&buf, c, p, &i); APPEND(buf); buf.p[buf.n - 1] = c; } p += i; if (a->things.n && a->things.p[a->things.n - 1].t == TT_SLICE && IS(a->slices.p[a->things.p[a->things.n - 1].i].p, a->slices.p[a->things.p[a->things.n - 1].i].n, ".include")) { APPEND(buf); buf.p[buf.n - 1] = '\0'; --a->things.n; if ((path2 = FindInclude(a, buf.p))) { Tokenize(a, StrDup(a, path2)); free(path2); free(buf.p); } else { Fail(a, "not found: %s", buf.p); } } else { SaveString(&a->strings, buf.p); AppendThing(a); a->things.p[a->things.n - 1].t = TT_SLICE; a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); a->things.p[a->things.n - 1].i = a->slices.n; AppendSlice(a); a->slices.p[a->slices.n - 1] = buf; } continue; } if (IsPunctMergeable(c) && a->things.n && a->things.p[a->things.n - 1].t == TT_PUNCT && IsPunctMergeable(a->things.p[a->things.n - 1].i)) { a->things.p[a->things.n - 1].i = a->things.p[a->things.n - 1].i << 8 | c; } else { AppendThing(a); a->things.p[a->things.n - 1].t = TT_PUNCT; a->things.p[a->things.n - 1].s = AppendSauce(a, path, line); a->things.p[a->things.n - 1].i = c; } ++p; } } static int GetSymbol(struct As *a, int name) { struct HashEntry *p; unsigned i, j, k, n, m, h; if (!(h = crc32c(0, a->slices.p[name].p, a->slices.p[name].n))) h = 1; n = a->symbolindex.n; i = 0; if (n) { k = 0; for (;;) { i = (h + k + ((k + 1) >> 1)) & (n - 1); if (a->symbolindex.p[i].h == h && a->slices.p[a->symbols.p[a->symbolindex.p[i].i].name].n == a->slices.p[name].n && !memcmp(a->slices.p[a->symbols.p[a->symbolindex.p[i].i].name].p, a->slices.p[name].p, a->slices.p[name].n)) { ++as_hashmap_hits; return a->symbolindex.p[i].i; } if (!a->symbolindex.p[i].h) { break; } else { ++k; ++as_hashmap_miss; } } } if (++a->symbolindex.i >= (n >> 1)) { m = n ? n << 1 : 16; p = calloc(m, sizeof(struct HashEntry)); for (j = 0; j < n; ++j) { if (a->symbolindex.p[j].h) { k = 0; do { i = (a->symbolindex.p[j].h + k + ((k + 1) >> 1)) & (m - 1); ++k; } while (p[i].h); p[i].h = a->symbolindex.p[j].h; p[i].i = a->symbolindex.p[j].i; } } k = 0; do { i = (h + k + ((k + 1) >> 1)) & (m - 1); ++k; } while (p[i].h); free(a->symbolindex.p); a->symbolindex.p = p; a->symbolindex.n = m; } APPEND(a->symbols); memset(a->symbols.p + a->symbols.n - 1, 0, sizeof(*a->symbols.p)); a->symbolindex.p[i].h = h; a->symbolindex.p[i].i = a->symbols.n - 1; a->symbols.p[a->symbols.n - 1].name = name; return a->symbols.n - 1; } static void OnSymbol(struct As *a, int name) { int i = GetSymbol(a, name); if (a->symbols.p[i].section) { Fail(a, "already defined: %.*s", a->slices.p[name].n, a->slices.p[name].p); } a->symbols.p[i].section = a->section; a->symbols.p[i].offset = a->sections.p[a->section].binary.n; a->i += 2; } static void OnLocalLabel(struct As *a, int id) { int i; char *name; name = xasprintf(".Label.%d", a->counter++); SaveString(&a->strings, name); AppendSlice(a); a->slices.p[a->slices.n - 1].p = name; a->slices.p[a->slices.n - 1].n = strlen(name); i = GetSymbol(a, a->slices.n - 1); a->symbols.p[i].section = a->section; a->symbols.p[i].offset = a->sections.p[a->section].binary.n; APPEND(a->labels); a->labels.p[a->labels.n - 1].id = id; a->labels.p[a->labels.n - 1].tok = a->i; a->labels.p[a->labels.n - 1].symbol = i; a->i += 2; } static void SetSection(struct As *a, int section) { a->previous = a->section; a->section = section; } static bool IsInt(struct As *a, int i) { return a->things.p[i].t == TT_INT; } static bool IsFloat(struct As *a, int i) { return a->things.p[i].t == TT_FLOAT; } static bool IsSlice(struct As *a, int i) { return a->things.p[i].t == TT_SLICE; } static bool IsPunct(struct As *a, int i, int c) { return a->things.p[i].t == TT_PUNCT && a->things.p[i].i == c; } static bool IsForward(struct As *a, int i) { return a->things.p[i].t == TT_FORWARD; } static bool IsBackward(struct As *a, int i) { return a->things.p[i].t == TT_BACKWARD; } static bool IsComma(struct As *a) { return IsPunct(a, a->i, ','); } static bool IsSemicolon(struct As *a) { return IsPunct(a, a->i, ';'); } static bool IsRegister(struct As *a, int i) { return IsSlice(a, i) && (a->slices.p[a->things.p[i].i].n && *a->slices.p[a->things.p[i].i].p == '%'); } static void ConsumePunct(struct As *a, int c) { char pb[4]; if (IsPunct(a, a->i, c)) { ++a->i; } else { Fail(a, "expected %s", PunctToStr(c, pb)); } } static void ConsumeComma(struct As *a) { ConsumePunct(a, ','); } static int NewPrimary(struct As *a, enum ExprKind k, int128_t x) { AppendExpr(a); a->exprs.p[a->exprs.n - 1].kind = k; a->exprs.p[a->exprs.n - 1].x = x; return a->exprs.n - 1; } static int NewUnary(struct As *a, enum ExprKind k, int lhs) { AppendExpr(a); a->exprs.p[a->exprs.n - 1].kind = k; a->exprs.p[a->exprs.n - 1].lhs = lhs; return a->exprs.n - 1; } static int NewBinary(struct As *a, enum ExprKind k, int lhs, int rhs) { AppendExpr(a); a->exprs.p[a->exprs.n - 1].kind = k; a->exprs.p[a->exprs.n - 1].lhs = lhs; a->exprs.p[a->exprs.n - 1].rhs = rhs; return a->exprs.n - 1; } // primary = int // | symbol // | reference static int ParsePrimary(struct As *a, int *rest, int i) { if (IsInt(a, i)) { *rest = i + 1; return NewPrimary(a, EX_INT, a->ints.p[a->things.p[i].i]); } else if (IsForward(a, i) || IsBackward(a, i) || (IsSlice(a, i) && (a->slices.p[a->things.p[i].i].n && a->slices.p[a->things.p[i].i].p[0] != '%' && a->slices.p[a->things.p[i].i].p[0] != '@'))) { *rest = i + 1; return NewPrimary(a, EX_SYM, i); } else { Fail(a, "expected int or label"); } } // postfix = primary "@gotpcrel" // | primary "@dtpoff" // | primary "@tpoff" // | primary static int ParsePostfix(struct As *a, int *rest, int i) { int x; struct Slice suffix; x = ParsePrimary(a, &i, i); if (IsSlice(a, i)) { suffix = a->slices.p[a->things.p[i].i]; if (suffix.n && suffix.p[0] == '@') { if (IS(suffix.p, suffix.n, "@gotpcrel")) { a->exprs.p[x].em = EM_GOTPCREL; ++i; } else if (IS(suffix.p, suffix.n, "@dtpoff")) { a->exprs.p[x].em = EM_DTPOFF; ++i; } else if (IS(suffix.p, suffix.n, "@tpoff")) { a->exprs.p[x].em = EM_TPOFF; ++i; } } } *rest = i; return x; } // unary = ("+" | "-" | "!" | "~") unary // | postfix static int ParseUnary(struct As *a, int *rest, int i) { int x; if (IsPunct(a, i, '+')) { x = ParseUnary(a, rest, i + 1); } else if (IsPunct(a, i, '-')) { x = ParseUnary(a, rest, i + 1); if (a->exprs.p[x].kind == EX_INT) { a->exprs.p[x].x = -a->exprs.p[x].x; } else { x = NewPrimary(a, EX_NEG, x); } } else if (IsPunct(a, i, '!')) { x = ParseUnary(a, rest, i + 1); if (a->exprs.p[x].kind == EX_INT) { a->exprs.p[x].x = !a->exprs.p[x].x; } else { x = NewPrimary(a, EX_NOT, x); } } else if (IsPunct(a, i, '~')) { x = ParseUnary(a, rest, i + 1); if (a->exprs.p[x].kind == EX_INT) { a->exprs.p[x].x = ~a->exprs.p[x].x; } else { x = NewPrimary(a, EX_BITNOT, x); } } else { x = ParsePostfix(a, rest, i); } return x; } // mul = unary ("*" unary | "/" unary | "%" unary)* static int ParseMul(struct As *a, int *rest, int i) { int x, y; x = ParseUnary(a, &i, i); for (;;) { if (IsPunct(a, i, '*')) { y = ParseUnary(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x *= a->exprs.p[y].x; } else { x = NewBinary(a, EX_MUL, x, y); } } else if (IsPunct(a, i, '/')) { y = ParseUnary(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x /= a->exprs.p[y].x; } else { x = NewBinary(a, EX_DIV, x, y); } } else if (IsPunct(a, i, '%')) { y = ParseUnary(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x %= a->exprs.p[y].x; } else { x = NewBinary(a, EX_REM, x, y); } } else { *rest = i; return x; } } } // add = mul ("+" mul | "-" mul)* static int ParseAdd(struct As *a, int *rest, int i) { int x, y; x = ParseMul(a, &i, i); for (;;) { if (IsPunct(a, i, '+')) { y = ParseMul(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x += a->exprs.p[y].x; } else { x = NewBinary(a, EX_ADD, x, y); } } else if (IsPunct(a, i, '-')) { y = ParseMul(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x -= a->exprs.p[y].x; } else if (a->exprs.p[y].kind == EX_INT) { a->exprs.p[y].x = -a->exprs.p[y].x; x = NewBinary(a, EX_ADD, x, y); } else { x = NewBinary(a, EX_SUB, x, y); } } else { *rest = i; return x; } } } // shift = add ("<<" add | ">>" add)* static int ParseShift(struct As *a, int *rest, int i) { int x, y; x = ParseAdd(a, &i, i); for (;;) { if (IsPunct(a, i, '<' << 8 | '<')) { y = ParseAdd(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x <<= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHL, x, y); } } else if (IsPunct(a, i, '>' << 8 | '>')) { y = ParseAdd(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x >>= a->exprs.p[y].x & 63; } else { x = NewBinary(a, EX_SHR, x, y); } } else { *rest = i; return x; } } } // relational = shift ("<" shift | "<=" shift | ">" shift | ">=" shift)* static int ParseRelational(struct As *a, int *rest, int i) { int x, y; x = ParseShift(a, &i, i); for (;;) { if (IsPunct(a, i, '<')) { y = ParseShift(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x < a->exprs.p[y].x; } else { x = NewBinary(a, EX_LT, x, y); } } else if (IsPunct(a, i, '>')) { y = ParseShift(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x < a->exprs.p[x].x; } else { x = NewBinary(a, EX_LT, y, x); } } else if (IsPunct(a, i, '<' << 8 | '=')) { y = ParseShift(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x <= a->exprs.p[y].x; } else { x = NewBinary(a, EX_LE, x, y); } } else if (IsPunct(a, i, '>' << 8 | '=')) { y = ParseShift(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[y].x <= a->exprs.p[x].x; } else { x = NewBinary(a, EX_LE, y, x); } } else { *rest = i; return x; } } } // equality = relational ("==" relational | "!=" relational)* static int ParseEquality(struct As *a, int *rest, int i) { int x, y; x = ParseRelational(a, &i, i); for (;;) { if (IsPunct(a, i, '=' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x; } else { x = NewBinary(a, EX_EQ, x, y); } } else if (IsPunct(a, i, '!' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x; } else { x = NewBinary(a, EX_NE, x, y); } } else { *rest = i; return x; } } } // and = equality ("&" equality)* static int ParseAnd(struct As *a, int *rest, int i) { int x, y; x = ParseEquality(a, &i, i); for (;;) { if (IsPunct(a, i, '&')) { y = ParseEquality(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x &= a->exprs.p[y].x; } else { x = NewBinary(a, EX_AND, x, y); } } else { *rest = i; return x; } } } // xor = and ("^" and)* static int ParseXor(struct As *a, int *rest, int i) { int x, y; x = ParseAnd(a, &i, i); for (;;) { if (IsPunct(a, i, '^')) { y = ParseAnd(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x ^= a->exprs.p[y].x; } else { x = NewBinary(a, EX_XOR, x, y); } } else { *rest = i; return x; } } } // or = xor ("|" xor)* static int ParseOr(struct As *a, int *rest, int i) { int x, y; x = ParseXor(a, &i, i); for (;;) { if (IsPunct(a, i, '|')) { y = ParseXor(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) { a->exprs.p[x].x |= a->exprs.p[y].x; } else { x = NewBinary(a, EX_OR, x, y); } } else { *rest = i; return x; } } } static int Parse(struct As *a) { return ParseOr(a, &a->i, a->i); } static int128_t GetInt(struct As *a) { int x; x = Parse(a); if (a->exprs.p[x].kind == EX_INT) { return a->exprs.p[x].x; } else { Fail(a, "expected constexpr int"); } } static long double GetFloat(struct As *a) { long double res; if (IsFloat(a, a->i)) { res = a->floats.p[a->things.p[a->i].i]; ++a->i; return res; } else { Fail(a, "expected float"); } } static struct Slice GetSlice(struct As *a) { struct Slice res; if (IsSlice(a, a->i)) { res = a->slices.p[a->things.p[a->i].i]; ++a->i; return res; } else { Fail(a, "expected string"); } } static void EmitData(struct As *a, const void *p, uint128_t n) { struct Slice *s; s = &a->sections.p[a->section].binary; s->p = realloc(s->p, s->n + n); if (n) memcpy(s->p + s->n, p, n); s->n += n; } static void EmitByte(struct As *a, uint128_t i) { uint8_t x = i; unsigned char b[1]; b[0] = (x & 0xff) >> 000; EmitData(a, b, 1); } static void EmitWord(struct As *a, uint128_t i) { uint16_t x = i; unsigned char b[2]; b[0] = (x & 0x00ff) >> 000; b[1] = (x & 0xff00) >> 010; EmitData(a, b, 2); } static void EmitLong(struct As *a, uint128_t i) { uint32_t x = i; unsigned char b[4]; b[0] = (x & 0x000000ff) >> 000; b[1] = (x & 0x0000ff00) >> 010; b[2] = (x & 0x00ff0000) >> 020; b[3] = (x & 0xff000000) >> 030; EmitData(a, b, 4); } void EmitQuad(struct As *a, uint128_t i) { uint64_t x = i; unsigned char b[8]; b[0] = (x & 0x00000000000000ff) >> 000; b[1] = (x & 0x000000000000ff00) >> 010; b[2] = (x & 0x0000000000ff0000) >> 020; b[3] = (x & 0x00000000ff000000) >> 030; b[4] = (x & 0x000000ff00000000) >> 040; b[5] = (x & 0x0000ff0000000000) >> 050; b[6] = (x & 0x00ff000000000000) >> 060; b[7] = (x & 0xff00000000000000) >> 070; EmitData(a, b, 8); } void EmitOcta(struct As *a, uint128_t i) { EmitQuad(a, i); EmitQuad(a, i >> 64); } static void EmitVarword(struct As *a, unsigned long x) { if (x > 255) EmitVarword(a, x >> 8); EmitByte(a, x); } static void OnSleb128(struct As *a, struct Slice s) { int c; int128_t x; for (;;) { x = GetInt(a); for (;;) { c = x & 0x7f; x >>= 7; if ((x == 0 && !(c & 0x40)) || (x == -1 && (c & 0x40))) { break; } else { c |= 0x80; } EmitByte(a, c); if (IsSemicolon(a)) break; ConsumeComma(a); } } } static void OnUleb128(struct As *a, struct Slice s) { int c; uint128_t x; for (;;) { x = GetInt(a); do { c = x & 0x7f; x >>= 7; if (x) c |= 0x80; EmitByte(a, c); } while (x); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnZleb128(struct As *a, struct Slice s) { int c; uint128_t x; for (;;) { x = GetInt(a); x = (x << 1) ^ ((int128_t)x >> 127); do { c = x & 0x7f; x >>= 7; if (x) c |= 0x80; EmitByte(a, c); } while (x); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnZero(struct As *a, struct Slice s) { long n; char *p; for (;;) { n = GetInt(a); p = calloc(n, 1); EmitData(a, p, n); free(p); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnSpace(struct As *a, struct Slice s) { long n; char *p; int fill; p = malloc((n = GetInt(a))); if (IsComma(a)) { ConsumeComma(a); fill = GetInt(a); } else { fill = 0; } memset(p, fill, n); EmitData(a, p, n); free(p); } static long GetRelaAddend(int kind) { switch (kind) { case R_X86_64_PC8: return -1; case R_X86_64_PC16: return -2; case R_X86_64_PC32: case R_X86_64_PLT32: case R_X86_64_GOTPCRELX: return -4; default: return 0; } } static void EmitExpr(struct As *a, int expr, int kind, void emitter(struct As *, uint128_t)) { if (expr == -1) { emitter(a, 0); } else if (a->exprs.p[expr].kind == EX_INT) { emitter(a, a->exprs.p[expr].x); } else { AppendRela(a); a->relas.p[a->relas.n - 1].kind = kind; a->relas.p[a->relas.n - 1].expr = expr; a->relas.p[a->relas.n - 1].section = a->section; a->relas.p[a->relas.n - 1].offset = a->sections.p[a->section].binary.n; a->relas.p[a->relas.n - 1].addend = GetRelaAddend(kind); emitter(a, 0); } } static void OpInt(struct As *a, int kind, void emitter(struct As *, uint128_t)) { for (;;) { EmitExpr(a, Parse(a), kind, emitter); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnByte(struct As *a, struct Slice s) { OpInt(a, R_X86_64_8, EmitByte); } static void OnWord(struct As *a, struct Slice s) { OpInt(a, R_X86_64_16, EmitWord); } static void OnLong(struct As *a, struct Slice s) { OpInt(a, R_X86_64_32, EmitLong); } static void OnQuad(struct As *a, struct Slice s) { OpInt(a, R_X86_64_64, EmitQuad); } static void OnOcta(struct As *a, struct Slice s) { OpInt(a, R_X86_64_64, EmitOcta); } static void OnFloat(struct As *a, struct Slice s) { float f; char b[4]; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else { f = GetInt(a); } memcpy(b, &f, 4); EmitData(a, b, 4); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnDouble(struct As *a, struct Slice s) { double f; char b[8]; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else { f = GetInt(a); } memcpy(b, &f, 8); EmitData(a, b, 8); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnLongDouble(struct As *a, int n) { char b[16]; long double f; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else { f = GetInt(a); } bzero(b, 16); memcpy(b, &f, sizeof(f)); EmitData(a, b, n); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnFloat80(struct As *a, struct Slice s) { OnLongDouble(a, 10); } static void OnLdbl(struct As *a, struct Slice s) { OnLongDouble(a, 16); } static void OnAscii(struct As *a, struct Slice s) { struct Slice arg; for (;;) { arg = GetSlice(a); EmitData(a, arg.p, arg.n); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnAsciz(struct As *a, struct Slice s) { struct Slice arg; for (;;) { arg = GetSlice(a); EmitData(a, arg.p, arg.n); EmitByte(a, 0); if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnAbort(struct As *a, struct Slice s) { Fail(a, "aborted"); } static void OnErr(struct As *a, struct Slice s) { if (a->inhibiterr) return; Fail(a, "error"); } static void OnError(struct As *a, struct Slice s) { struct Slice msg = GetSlice(a); if (a->inhibiterr) return; Fail(a, "%.*s", msg.n, msg.p); } static void OnWarning(struct As *a, struct Slice s) { struct Slice msg = GetSlice(a); if (a->inhibitwarn) return; PrintLocation(a); fprintf(stderr, "%.*s\n", msg.n, msg.p); } static void OnText(struct As *a, struct Slice s) { SetSection(a, 1); } static void OnData(struct As *a, struct Slice s) { SetSection(a, 2); } static void OnBss(struct As *a, struct Slice s) { SetSection(a, 3); } static void OnPrevious(struct As *a, struct Slice s) { SetSection(a, a->previous); } static void OnAlign(struct As *a, struct Slice s) { long i, n, align, fill, maxskip; align = GetInt(a); if (!IS2POW(align)) Fail(a, "alignment not power of 2"); fill = (a->sections.p[a->section].flags & SHF_EXECINSTR) ? 0x90 : 0; maxskip = 268435456; if (IsComma(a)) { ++a->i; fill = GetInt(a); if (IsComma(a)) { ++a->i; maxskip = GetInt(a); } } i = a->sections.p[a->section].binary.n; n = ROUNDUP(i, align) - i; if (n > maxskip) return; a->sections.p[a->section].align = MAX(a->sections.p[a->section].align, align); for (i = 0; i < n; ++i) EmitByte(a, fill); } static int SectionFlag(struct As *a, int c) { switch (c) { case 'a': return SHF_ALLOC; case 'w': return SHF_WRITE; case 'x': return SHF_EXECINSTR; case 'g': return SHF_GROUP; case 'M': return SHF_MERGE; case 'S': return SHF_STRINGS; case 'T': return SHF_TLS; default: Fail(a, "unknown section flag: %`'c", c); } } static int SectionFlags(struct As *a, struct Slice s) { int i, flags; for (flags = i = 0; i < s.n; ++i) { flags |= SectionFlag(a, s.p[i]); } return flags; } static int SectionType(struct As *a, struct Slice s) { if (IS(s.p, s.n, "@progbits") || IS(s.p, s.n, "SHT_PROGBITS")) { return SHT_PROGBITS; } else if (IS(s.p, s.n, "@note") || IS(s.p, s.n, "SHT_NOTE")) { return SHT_NOTE; } else if (IS(s.p, s.n, "@nobits") || IS(s.p, s.n, "SHT_NOBITS")) { return SHT_NOBITS; } else if (IS(s.p, s.n, "@preinit_array") || IS(s.p, s.n, "SHT_PREINIT_ARRAY")) { return SHT_PREINIT_ARRAY; } else if (IS(s.p, s.n, "@init_array") || IS(s.p, s.n, "SHT_INIT_ARRAY")) { return SHT_INIT_ARRAY; } else if (IS(s.p, s.n, "@fini_array") || IS(s.p, s.n, "SHT_FINI_ARRAY")) { return SHT_FINI_ARRAY; } else { Fail(a, "unknown section type: %.*s", s.n, s.p); } } static int SymbolType(struct As *a, struct Slice s) { if (IS(s.p, s.n, "@object") || IS(s.p, s.n, "STT_OBJECT")) { return STT_OBJECT; } else if (IS(s.p, s.n, "@function") || IS(s.p, s.n, "STT_FUNC")) { return STT_FUNC; } else if (IS(s.p, s.n, "@common") || IS(s.p, s.n, "STT_COMMON")) { return STT_COMMON; } else if (IS(s.p, s.n, "@notype") || IS(s.p, s.n, "STT_NOTYPE")) { return STT_NOTYPE; } else if (IS(s.p, s.n, "@tls_object") || IS(s.p, s.n, "STT_TLS")) { return STT_TLS; } else { Fail(a, "unknown symbol type: %.*s", s.n, s.p); } } static int GrabSection(struct As *a, int name, int flags, int type, int group, int comdat) { int i; for (i = 0; i < a->sections.n; ++i) { if (!strcmp(a->strings.p[name], a->strings.p[a->sections.p[i].name])) { return i; } } return AppendSection(a, name, flags, type); } static void OnSection(struct As *a, struct Slice s) { int name, flags, type, group = -1, comdat = -1; name = SliceDup(a, GetSlice(a)); if (startswith(a->strings.p[name], ".text")) { flags = SHF_ALLOC | SHF_EXECINSTR; type = SHT_PROGBITS; } else if (startswith(a->strings.p[name], ".data")) { flags = SHF_ALLOC | SHF_WRITE; type = SHT_PROGBITS; } else if (startswith(a->strings.p[name], ".bss")) { flags = SHF_ALLOC | SHF_WRITE; type = SHT_NOBITS; } else { flags = SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE; type = SHT_PROGBITS; } if (IsComma(a)) { ++a->i; flags = SectionFlags(a, GetSlice(a)); if (IsComma(a)) { ++a->i; type = SectionType(a, GetSlice(a)); if (IsComma(a)) { ++a->i; group = SectionType(a, GetSlice(a)); if (IsComma(a)) { ++a->i; comdat = SectionType(a, GetSlice(a)); } } } } SetSection(a, GrabSection(a, name, flags, type, group, comdat)); } static void OnPushsection(struct As *a, struct Slice s) { APPEND(a->sectionstack); a->sectionstack.p[a->sectionstack.n - 1] = a->section; OnSection(a, s); } static void OnPopsection(struct As *a, struct Slice s) { if (!a->sectionstack.n) Fail(a, "stack smashed"); a->section = a->sectionstack.p[--a->sectionstack.n]; } static void OnIdent(struct As *a, struct Slice s) { struct Slice arg; int comment, oldsection; comment = GrabSection(a, StrDup(a, ".comment"), SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, -1, -1); oldsection = a->section; a->section = comment; arg = GetSlice(a); EmitData(a, arg.p, arg.n); EmitByte(a, 0); a->section = oldsection; } static void OnIncbin(struct As *a, struct Slice s) { int fd; struct stat st; char *path, *path2; struct Slice *data, arg; arg = GetSlice(a); path = strndup(arg.p, arg.n); if ((path2 = FindInclude(a, path))) { if ((fd = open(path2, O_RDONLY)) == -1 || fstat(fd, &st) == -1) { Fail(a, "open failed: %s", path2); } data = &a->sections.p[a->section].binary; data->p = realloc(data->p, data->n + st.st_size); if (read(fd, data->p, st.st_size) != st.st_size) { Fail(a, "read failed: %s", path2); } data->n += st.st_size; close(fd); free(path2); } else { Fail(a, "not found: %s", path); } free(path); } static void OnType(struct As *a, struct Slice s) { int i; i = GetSymbol(a, a->things.p[a->i++].i); ConsumeComma(a); a->symbols.p[i].type = SymbolType(a, GetSlice(a)); } static void OnSize(struct As *a, struct Slice s) { int i; i = GetSymbol(a, a->things.p[a->i++].i); ConsumeComma(a); a->symbols.p[i].size = GetInt(a); } static void OnEqu(struct As *a, struct Slice s) { int i; i = GetSymbol(a, a->things.p[a->i++].i); ConsumeComma(a); a->symbols.p[i].offset = GetInt(a); a->symbols.p[i].section = SHN_ABS; } static void OnComm(struct As *a, struct Slice s) { int i; i = GetSymbol(a, a->things.p[a->i++].i); ConsumeComma(a); a->symbols.p[i].size = GetInt(a); a->symbols.p[i].type = STT_COMMON; a->symbols.p[i].section = SHN_COMMON; } static void OpVisibility(struct As *a, int visibility) { int i; for (;;) { i = GetSymbol(a, a->things.p[a->i++].i); a->symbols.p[i].stv = visibility; if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnInternal(struct As *a, struct Slice s) { OpVisibility(a, STV_INTERNAL); } static void OnHidden(struct As *a, struct Slice s) { OpVisibility(a, STV_HIDDEN); } static void OnProtected(struct As *a, struct Slice s) { OpVisibility(a, STV_PROTECTED); } static void OpBind(struct As *a, int bind) { int i; for (;;) { i = GetSymbol(a, a->things.p[a->i++].i); a->symbols.p[i].stb = bind; if (IsSemicolon(a)) break; ConsumeComma(a); } } static void OnLocal(struct As *a, struct Slice s) { OpBind(a, STB_LOCAL); } static void OnWeak(struct As *a, struct Slice s) { OpBind(a, STB_WEAK); } static void OnGlobal(struct As *a, struct Slice s) { OpBind(a, STB_GLOBAL); } static int GetOpSize(struct As *a, struct Slice s, int modrm, int i) { if (modrm & ISREG) { return (modrm & 070) >> 3; } else { switch (s.p[s.n - i]) { case 'b': case 'B': return 0; case 'w': case 'W': return 1; case 'l': case 'L': return 2; case 'q': case 'Q': return 3; default: Fail(a, "could not size instruction"); } } } static bool ConsumeSegment(struct As *a) { int i; struct Slice s; if (IsSlice(a, a->i)) { s = a->slices.p[a->things.p[a->i].i]; if (s.n == 3 && *s.p == '%') { for (i = 0; i < ARRAYLEN(kSegment); ++i) { if (s.p[1] == kSegment[i][0] && s.p[2] == kSegment[i][1]) { ++a->i; EmitByte(a, kSegmentByte[i]); ConsumePunct(a, ':'); return true; } } } } return false; } static void CopyLower(char *k, const char *p, int n) { int i; for (i = 0; i < n; ++i) { k[i] = tolower(p[i]); } } static unsigned long MakeKey64(const char *p, int n) { char k[8] = {0}; CopyLower(k, p, n); return READ64BE(k); } static uint128_t MakeKey128(const char *p, int n) { char k[16] = {0}; CopyLower(k, p, n); return READ128BE(k); } static bool Prefix(struct As *a, const char *p, int n) { int m, l, r; unsigned long x, y; if (n && n <= 8) { x = MakeKey64(p, n); l = 0; r = ARRAYLEN(kPrefix) - 1; while (l <= r) { m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kPrefix[m]); if (x < y) { r = m - 1; } else if (x > y) { l = m + 1; } else { EmitByte(a, kPrefixByte[m]); return true; } } } return false; } static bool FindReg(const char *p, int n, struct Reg *out_reg) { int m, l, r; unsigned long x, y; if (n && n <= 8 && *p == '%') { ++p; --n; x = MakeKey64(p, n); l = 0; r = ARRAYLEN(kRegs) - 1; while (l <= r) { m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kRegs[m].s); if (x < y) { r = m - 1; } else if (x > y) { l = m + 1; } else { *out_reg = kRegs[m]; return true; } } } return false; } static int FindRegReg(struct Slice s) { struct Reg reg; if (!FindReg(s.p, s.n, ®)) return -1; return reg.reg; } static int FindRegRm(struct Slice s) { struct Reg reg; if (!FindReg(s.p, s.n, ®)) return -1; return reg.rm; } static int FindRegBase(struct Slice s) { struct Reg reg; if (!FindReg(s.p, s.n, ®)) return -1; return reg.base; } static int FindRegIndex(struct Slice s) { struct Reg reg; if (!FindReg(s.p, s.n, ®)) return -1; return reg.index; } static int RemoveRexw(int x) { if (x == -1) return x; x &= ~0x0800; if (((x & 0xff00) >> 8) == REX) x &= ~0xff00; return x; } static int GetRegisterReg(struct As *a) { int reg; if ((reg = FindRegReg(GetSlice(a))) == -1) { InvalidRegister(a); } return reg; } static int GetRegisterRm(struct As *a) { int reg; if ((reg = FindRegRm(GetSlice(a))) == -1) { InvalidRegister(a); } return reg; } static int ParseModrm(struct As *a, int *disp) { /* ┌isreg │┌isrip ││┌hasindex │││┌hasbase ││││┌hasasz │││││┌rex ││││││ ┌scale ││││││ │ ┌index or size ││││││ │ │ ┌base or reg │││││├──────┐├┐├─┐├─┐ 0b00000000000000000000000000000000*/ struct Slice str; int reg, modrm = 0; if (!ConsumeSegment(a) && IsRegister(a, a->i)) { *disp = 0; modrm = GetRegisterRm(a) | ISREG; } else { if (!IsPunct(a, a->i, '(')) { *disp = Parse(a); } else { *disp = -1; } if (IsPunct(a, a->i, '(')) { ++a->i; if (!IsComma(a)) { str = GetSlice(a); modrm |= HASBASE; if (!strncasecmp(str.p, "%rip", str.n)) { modrm |= ISRIP; } else { reg = FindRegBase(str); if (reg == -1) InvalidRegister(a); modrm |= reg & 007; // reg modrm |= reg & 0xff00; // rex if (((reg & 070) >> 3) == 2) modrm |= HASASZ; // asz } } if (IsComma(a)) { ++a->i; modrm |= HASINDEX; reg = FindRegIndex(GetSlice(a)); if (reg == -1) InvalidRegister(a); modrm |= (reg & 007) << 3; // index modrm |= reg & 0xff00; // rex if (((reg & 070) >> 3) == 2) modrm |= HASASZ; // asz if (IsComma(a)) { ++a->i; modrm |= (bsr(GetInt(a)) & 3) << 6; } } ConsumePunct(a, ')'); } if (modrm & HASASZ) { EmitByte(a, ASZ); } } return modrm; } static void EmitImm(struct As *a, int reg, int imm) { switch ((reg & 030) >> 3) { case 0: EmitExpr(a, imm, R_X86_64_8, EmitByte); break; case 1: EmitExpr(a, imm, R_X86_64_16, EmitWord); break; case 2: case 3: EmitExpr(a, imm, R_X86_64_32S, EmitLong); break; default: abort(); } } static void EmitModrm(struct As *a, int reg, int modrm, int disp) { int relo, mod; void (*emitter)(struct As *, uint128_t); reg &= 7; reg <<= 3; if (modrm & ISREG) { EmitByte(a, 0300 | reg | (modrm & 7)); } else { if (modrm & ISRIP) { EmitByte(a, 005 | reg); emitter = EmitLong; relo = a->pcrelative ?: R_X86_64_PC32; } else if (modrm & (HASBASE | HASINDEX)) { if (disp == -1) { emitter = NULL; relo = 0; mod = 0; } else if (a->exprs.p[disp].kind == EX_INT) { if (!a->exprs.p[disp].x) { emitter = NULL; relo = 0; mod = 0; } else if (-128 <= a->exprs.p[disp].x && a->exprs.p[disp].x <= 127) { emitter = EmitByte; relo = R_X86_64_32S; mod = 0100; } else { emitter = EmitLong; relo = R_X86_64_32S; mod = 0200; } } else { emitter = EmitLong; relo = R_X86_64_32S; mod = 0200; } if (!(modrm & HASINDEX) && (modrm & 7) != 4) { EmitByte(a, mod | reg | modrm); } else if (!(modrm & HASINDEX) && (modrm & 7) == 4) { EmitByte(a, mod | reg | 4); // (%rsp) must be (%rsp,%riz) EmitByte(a, 040 | modrm); } else if (!mod && (modrm & 7) == 5) { EmitByte(a, 0100 | reg | 4); // (%rbp,𝑥) is special EmitByte(a, modrm); EmitByte(a, 0); } else { EmitByte(a, mod | reg | 4); EmitByte(a, modrm); } } else { EmitByte(a, 004 | reg); // (%rbp,%riz) is disp32 EmitByte(a, 045); emitter = EmitLong; relo = R_X86_64_32S; } if (emitter) { EmitExpr(a, disp, relo, emitter); } } } static void EmitRex(struct As *a, int x) { if (x & 0xff00) { EmitByte(a, x >> 8); } } static void EmitOpModrm(struct As *a, long op, int reg, int modrm, int disp, int skew) { switch ((reg & 070) >> 3) { case 0: EmitVarword(a, op); EmitModrm(a, reg, modrm, disp); break; case 1: EmitVarword(a, op + skew); EmitModrm(a, reg, modrm, disp); break; case 2: case 3: case 4: EmitVarword(a, op + skew); EmitModrm(a, reg, modrm, disp); break; default: abort(); } } static void EmitRexOpModrm(struct As *a, long op, int reg, int modrm, int disp, int skew) { if (((reg & 070) >> 3) == 1) EmitByte(a, OSZ); EmitRex(a, reg | modrm); EmitOpModrm(a, op, reg, modrm, disp, skew); } static void OnLoad(struct As *a, struct Slice s, int op) { int modrm, reg, disp; modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static void OnLea(struct As *a, struct Slice s) { return OnLoad(a, s, 0x8D); } static void OnLar(struct As *a, struct Slice s) { return OnLoad(a, s, 0x0f02); } static void OnLsl(struct As *a, struct Slice s) { return OnLoad(a, s, 0x0f03); } static void OnMov(struct As *a, struct Slice s) { int reg, modrm, disp, imm; if (IsPunct(a, a->i, '$')) { ++a->i; imm = Parse(a); ConsumeComma(a); if (IsSlice(a, a->i)) { // imm -> reg reg = GetRegisterRm(a); switch ((reg & 070) >> 3) { case 0: EmitRex(a, reg); EmitByte(a, 0xB0 + (reg & 7)); EmitExpr(a, imm, R_X86_64_8, EmitByte); break; case 1: EmitByte(a, OSZ); EmitRex(a, reg); EmitByte(a, 0xB8 + (reg & 7)); EmitExpr(a, imm, R_X86_64_16, EmitWord); break; case 2: EmitRex(a, reg); EmitByte(a, 0xB8 + (reg & 7)); EmitExpr(a, imm, R_X86_64_32, EmitLong); break; case 3: EmitRex(a, reg); EmitByte(a, 0xB8 + (reg & 7)); // suboptimal EmitExpr(a, imm, R_X86_64_64, EmitQuad); break; default: Fail(a, "todo movd/movq"); } } else { // imm -> modrm modrm = ParseModrm(a, &disp); switch (GetOpSize(a, s, modrm, 1)) { case 0: EmitRex(a, modrm); EmitByte(a, 0xC6); EmitModrm(a, 0, modrm, disp); EmitExpr(a, imm, R_X86_64_8, EmitByte); break; case 1: EmitByte(a, OSZ); EmitRex(a, modrm); EmitByte(a, 0xC7); EmitModrm(a, 0, modrm, disp); EmitExpr(a, imm, R_X86_64_16, EmitWord); break; case 2: EmitRex(a, modrm); EmitByte(a, 0xC7); EmitModrm(a, 0, modrm, disp); EmitExpr(a, imm, R_X86_64_32, EmitLong); break; case 3: EmitRex(a, modrm | REXW << 8); EmitByte(a, 0xC7); // suboptimal EmitModrm(a, 0, modrm, disp); EmitExpr(a, imm, R_X86_64_32, EmitLong); break; default: abort(); } } } else if (IsSlice(a, a->i)) { // reg -> reg/modrm reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x88, reg, modrm, disp, 1); } else { // modrm -> reg modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x8A, reg, modrm, disp, 1); } } static void EmitMovx(struct As *a, struct Slice opname, int op) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRex(a, reg); if (((reg & 070) >> 3) == 1) EmitByte(a, OSZ); EmitVarword(a, op + !!GetOpSize(a, opname, modrm, 2)); EmitModrm(a, reg, modrm, disp); } static void OnMovzbwx(struct As *a, struct Slice s) { EmitMovx(a, s, 0x0FB6); } static void OnMovsbwx(struct As *a, struct Slice s) { EmitMovx(a, s, 0x0FBE); } static void OnMovslq(struct As *a, struct Slice s) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitByte(a, REXW); EmitByte(a, 0x63); EmitModrm(a, reg, modrm, disp); } static dontinline void OpAluImpl(struct As *a, struct Slice opname, int op) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { // imm -> reg/modrm ++a->i; imm = Parse(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); reg = GetOpSize(a, opname, modrm, 1) << 3 | op; EmitRexOpModrm(a, 0x80, reg, modrm, disp, 1); // suboptimal EmitImm(a, reg, imm); } else if (IsSlice(a, a->i)) { // reg -> reg/modrm reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, op << 3, reg, modrm, disp, 1); } else { // modrm -> reg modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, op << 3 | 2, reg, modrm, disp, 1); } } static dontinline void OpAlu(struct As *a, struct Slice opname, int op) { OpAluImpl(a, opname, op); } static dontinline void OpBsuImpl(struct As *a, struct Slice opname, int op) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { ++a->i; imm = Parse(a); ConsumeComma(a); } else if (IsSlice(a, a->i) && (a->slices.p[a->things.p[a->i].i].n == 3 && !strncasecmp(a->slices.p[a->things.p[a->i].i].p, "%cl", 3)) && !IsPunct(a, a->i + 1, ';')) { ++a->i; ConsumeComma(a); modrm = ParseModrm(a, &disp); reg = GetOpSize(a, opname, modrm, 1) << 3 | op; EmitRexOpModrm(a, 0xD2, reg, modrm, disp, 1); return; } else { AppendExpr(a); a->exprs.p[a->exprs.n - 1].kind = EX_INT; a->exprs.p[a->exprs.n - 1].tok = a->i; a->exprs.p[a->exprs.n - 1].x = 1; imm = a->exprs.n - 1; } modrm = ParseModrm(a, &disp); reg = GetOpSize(a, opname, modrm, 1) << 3 | op; EmitRexOpModrm(a, 0xC0, reg, modrm, disp, 1); // suboptimal EmitExpr(a, imm, R_X86_64_8, EmitByte); } static dontinline void OpBsu(struct As *a, struct Slice opname, int op) { OpBsuImpl(a, opname, op); } static dontinline void OpXadd(struct As *a) { int reg, modrm, disp; reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0FC0, reg, modrm, disp, 1); } static dontinline int OpF6Impl(struct As *a, struct Slice s, int reg) { int modrm, disp; modrm = ParseModrm(a, &disp); reg |= GetOpSize(a, s, modrm, 1) << 3; EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1); return reg; } static dontinline int OpF6(struct As *a, struct Slice s, int reg) { return OpF6Impl(a, s, reg); } static void OnTest(struct As *a, struct Slice s) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { ++a->i; imm = Parse(a); ConsumeComma(a); reg = OpF6(a, s, 0); // suboptimal EmitImm(a, reg, imm); } else { reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x84, reg, modrm, disp, 1); } } static void OnCmpxchg(struct As *a, struct Slice s) { int reg, modrm, disp; reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0FB0, reg, modrm, disp, 1); } static void OnImul(struct As *a, struct Slice s) { int reg, modrm, imm, disp; if (IsPunct(a, a->i, '$')) { ++a->i; imm = Parse(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x69, reg, modrm, disp, 0); EmitImm(a, reg, imm); } else { modrm = ParseModrm(a, &disp); if (IsComma(a)) { ++a->i; reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x0FAF, reg, modrm, disp, 0); } else { reg = GetOpSize(a, s, modrm, 1) << 3 | 5; EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1); } } } static void OpBit(struct As *a, int op) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static void OnXchg(struct As *a, struct Slice s) { int reg, modrm, disp; reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x86, reg, modrm, disp, 1); } static void OpBump(struct As *a, struct Slice s, int reg) { int modrm, disp; modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0xFE, GetOpSize(a, s, modrm, 1) << 3 | reg, modrm, disp, 1); } static void OpShrld(struct As *a, struct Slice s, int op) { int imm, reg, modrm, disp, skew; if (IsSlice(a, a->i) && (a->slices.p[a->things.p[a->i].i].n == 3 && !strncasecmp(a->slices.p[a->things.p[a->i].i].p, "%cl", 3))) { ++a->i; ConsumeComma(a); skew = 1; reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0); } else { skew = 0; ConsumePunct(a, '$'); imm = GetInt(a); ConsumeComma(a); reg = GetRegisterReg(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0); EmitExpr(a, imm, R_X86_64_8, EmitByte); } } static void OnShrd(struct As *a, struct Slice s) { OpShrld(a, s, 0xAC); } static void OnShld(struct As *a, struct Slice s) { OpShrld(a, s, 0xA4); } static void OpSseMov(struct As *a, int opWsdVsd, int opVsdWsd) { int reg, modrm, disp; if (IsRegister(a, a->i)) { reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, opWsdVsd, reg, modrm, disp, 0); } else { modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, opVsdWsd, reg, modrm, disp, 0); } } static void OpMovntdq(struct As *a) { int reg, modrm, disp; reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x660FE7, reg, modrm, disp, 0); } static void OpMovdqx(struct As *a, int op) { OpSseMov(a, op + 0x10, op); } static void OnMovdqu(struct As *a, struct Slice s) { EmitByte(a, 0xF3); OpMovdqx(a, 0x0F6F); } static void OnMovups(struct As *a, struct Slice s) { OpSseMov(a, 0x0F11, 0x0F10); } static void OnMovupd(struct As *a, struct Slice s) { EmitByte(a, 0x66); OnMovups(a, s); } static void OnMovdqa(struct As *a, struct Slice s) { EmitByte(a, 0x66); OpMovdqx(a, 0x0F6F); } static void OnMovaps(struct As *a, struct Slice s) { OpSseMov(a, 0x0F29, 0x0F28); } static void OnMovapd(struct As *a, struct Slice s) { EmitByte(a, 0x66); OpSseMov(a, 0x0F29, 0x0F28); } static void OpMovdq(struct As *a, bool is64) { int reg, modrm, boop, disp, ugh; EmitByte(a, 0x66); // todo mmx if (IsRegister(a, a->i)) { reg = GetRegisterReg(a); ConsumeComma(a); modrm = ParseModrm(a, &disp); if (!(modrm & ISREG)) { if (((reg & 070) >> 3) == 4) { if (is64) reg |= REXW << 8; boop = 0x10; } else { boop = 0; } } else { if (((reg & 070) >> 3) == 4) { boop = 0x10; } else { boop = 0; ugh = modrm & 7; modrm &= ~7; modrm |= reg & 7; reg &= ~7; reg |= ugh; } } } else { modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); if (!(modrm & ISREG)) { if (((reg & 070) >> 3) == 4) { if (is64) reg |= REXW << 8; boop = 0; } else { boop = 0x10; } } else { boop = ((modrm & 070) >> 3) == 4 ? 0 : 0x10; } } EmitRexOpModrm(a, 0x0F6E + boop, reg, modrm, disp, 0); } static void OnMovss(struct As *a, struct Slice s) { OpSseMov(a, 0xF30F11, 0xF30F10); } static void OnMovsd(struct As *a, struct Slice s) { OpSseMov(a, 0xF20F11, 0xF20F10); } static bool IsSsePrefix(int c) { return c == 0x66 || c == 0xF2 || c == 0xF3; // must come before rex } static dontinline void OpSseImpl(struct As *a, int op) { int reg, modrm, disp; if (IsSsePrefix((op & 0xff000000) >> 24)) { EmitByte(a, (op & 0xff000000) >> 24); op &= 0xffffff; } if (IsSsePrefix((op & 0x00ff0000) >> 16)) { EmitByte(a, (op & 0x00ff0000) >> 16); op &= 0xffff; } modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static dontinline void OpSse(struct As *a, int op) { OpSseImpl(a, op); } static dontinline void OpSseIbImpl(struct As *a, int op) { int imm; ConsumePunct(a, '$'); imm = Parse(a); ConsumeComma(a); OpSse(a, op); EmitExpr(a, imm, R_X86_64_8, EmitByte); } static dontinline void OpSseIb(struct As *a, int op) { OpSseIbImpl(a, op); } static bool HasXmmOnLine(struct As *a) { int i; for (i = 0; !IsPunct(a, a->i + i, ';'); ++i) { if (IsSlice(a, a->i + i) && a->slices.p[a->things.p[a->i + i].i].n >= 4 && (startswith(a->slices.p[a->things.p[a->i + i].i].p, "xmm") || startswith(a->slices.p[a->things.p[a->i + i].i].p, "%xmm"))) { return true; } } return false; } static void OnMovd(struct As *a, struct Slice s) { OpMovdq(a, false); } static void OnMovq(struct As *a, struct Slice s) { if (HasXmmOnLine(a)) { OpMovdq(a, true); } else { OnMov(a, s); } } static void OnPush(struct As *a, struct Slice s) { int modrm, disp; if (IsPunct(a, a->i, '$')) { ++a->i; EmitByte(a, 0x68); EmitLong(a, GetInt(a)); } else { modrm = RemoveRexw(ParseModrm(a, &disp)); EmitRexOpModrm(a, 0xFF, 6, modrm, disp, 0); // suboptimal } } static void OnRdpid(struct As *a, struct Slice s) { EmitVarword(a, 0xf30fc7); EmitByte(a, 0370 | GetRegisterReg(a)); } static void OnPop(struct As *a, struct Slice s) { int modrm, disp; modrm = RemoveRexw(ParseModrm(a, &disp)); EmitRexOpModrm(a, 0x8F, 0, modrm, disp, 0); // suboptimal } static void OnNop(struct As *a, struct Slice opname) { int modrm, disp; if (IsSemicolon(a)) { EmitByte(a, 0x90); } else { modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F1F, 6, modrm, disp, 0); } } static void OnRet(struct As *a, struct Slice s) { if (IsPunct(a, a->i, '$')) { ++a->i; EmitByte(a, 0xC2); EmitWord(a, GetInt(a)); } else { EmitByte(a, 0xC3); } } static dontinline void OpCmovccImpl(struct As *a, int cc) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); ConsumeComma(a); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x0F40 | cc, reg, modrm, disp, 0); } static dontinline void OpCmovcc(struct As *a, int cc) { OpCmovccImpl(a, cc); } static dontinline void OpSetccImpl(struct As *a, int cc) { int modrm, disp; modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F90 | cc, 6, modrm, disp, 0); } static dontinline void OpSetcc(struct As *a, int cc) { OpSetccImpl(a, cc); } static void OnFile(struct As *a, struct Slice s) { int fileno; struct Slice path; fileno = GetInt(a); path = GetSlice(a); (void)fileno; (void)path; // TODO: DWARF } static void OnLoc(struct As *a, struct Slice s) { int fileno, lineno; fileno = GetInt(a); lineno = GetInt(a); (void)fileno; (void)lineno; // TODO: DWARF } static void OnCall(struct As *a, struct Slice s) { int modrm, disp; if (IsPunct(a, a->i, '*')) ++a->i; modrm = RemoveRexw(ParseModrm(a, &disp)); if (modrm & (ISREG | ISRIP | HASINDEX | HASBASE)) { if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX; EmitRexOpModrm(a, 0xFF, 2, modrm, disp, 0); a->pcrelative = 0; } else { EmitByte(a, 0xE8); EmitExpr(a, disp, R_X86_64_PC32, EmitLong); } } static dontinline void OpJmpImpl(struct As *a, int cc) { int modrm, disp; if (IsPunct(a, a->i, '*')) ++a->i; modrm = RemoveRexw(ParseModrm(a, &disp)); if (cc == -1) { if (modrm & (ISREG | ISRIP | HASINDEX | HASBASE)) { if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX; EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0); a->pcrelative = 0; } else { EmitByte(a, 0xE9); EmitExpr(a, disp, R_X86_64_PC32, EmitLong); } } else { EmitByte(a, 0x0F); EmitByte(a, 0x80 + cc); EmitExpr(a, disp, R_X86_64_PC32, EmitLong); } } static dontinline void OpJmp(struct As *a, int cc) { OpJmpImpl(a, cc); } static dontinline void OpFpu1Impl(struct As *a, int op, int reg) { int modrm, disp; modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static dontinline void OpFpu1(struct As *a, int op, int reg) { OpFpu1Impl(a, op, reg); } static void OnFxch(struct As *a, struct Slice s) { int rm; rm = !IsSemicolon(a) ? GetRegisterRm(a) : 1; EmitByte(a, 0xD9); EmitByte(a, 0310 | (rm & 7)); } static void OnBswap(struct As *a, struct Slice s) { int srm; srm = GetRegisterRm(a); EmitRex(a, srm); EmitByte(a, 0x0F); EmitByte(a, 0310 | (srm & 7)); } static dontinline void OpFcomImpl(struct As *a, int op) { int rm; if (IsSemicolon(a)) { rm = 1; } else { rm = GetRegisterRm(a); if (IsComma(a)) { ++a->i; if (GetRegisterReg(a) & 7) { Fail(a, "bad register"); } } } EmitVarword(a, op | (rm & 7)); } static dontinline void OpFcom(struct As *a, int op) { OpFcomImpl(a, op); } // clang-format off static void OnAdc(struct As *a, struct Slice s) { OpAlu(a, s, 2); } static void OnAdd(struct As *a, struct Slice s) { OpAlu(a, s, 0); } static void OnAddpd(struct As *a, struct Slice s) { OpSse(a, 0x660F58); } static void OnAddps(struct As *a, struct Slice s) { OpSse(a, 0x0F58); } static void OnAddsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F58); } static void OnAddss(struct As *a, struct Slice s) { OpSse(a, 0xF30F58); } static void OnAddsubpd(struct As *a, struct Slice s) { OpSse(a, 0x660FD0); } static void OnAddsubps(struct As *a, struct Slice s) { OpSse(a, 0xF20FD0); } static void OnAnd(struct As *a, struct Slice s) { OpAlu(a, s, 4); } static void OnAndnpd(struct As *a, struct Slice s) { OpSse(a, 0x660F55); } static void OnAndnps(struct As *a, struct Slice s) { OpSse(a, 0x0F55); } static void OnAndpd(struct As *a, struct Slice s) { OpSse(a, 0x660F54); } static void OnAndps(struct As *a, struct Slice s) { OpSse(a, 0x0F54); } static void OnBlendpd(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A0D); } static void OnBlendvpd(struct As *a, struct Slice s) { OpSse(a, 0x660F3815); } static void OnBsf(struct As *a, struct Slice s) { OpBit(a, 0x0FBC); } static void OnBsr(struct As *a, struct Slice s) { OpBit(a, 0x0FBD); } static void OnCbtw(struct As *a, struct Slice s) { EmitVarword(a, 0x6698); } static void OnClc(struct As *a, struct Slice s) { EmitByte(a, 0xF8); } static void OnCld(struct As *a, struct Slice s) { EmitByte(a, 0xFC); } static void OnCli(struct As *a, struct Slice s) { EmitByte(a, 0xFA); } static void OnCltd(struct As *a, struct Slice s) { EmitByte(a, 0x99); } static void OnCltq(struct As *a, struct Slice s) { EmitVarword(a, 0x4898); } static void OnCmc(struct As *a, struct Slice s) { EmitByte(a, 0xF5); } static void OnCmovb(struct As *a, struct Slice s) { OpCmovcc(a, 2); } static void OnCmovbe(struct As *a, struct Slice s) { OpCmovcc(a, 6); } static void OnCmovl(struct As *a, struct Slice s) { OpCmovcc(a, 12); } static void OnCmovle(struct As *a, struct Slice s) { OpCmovcc(a, 14); } static void OnCmovnb(struct As *a, struct Slice s) { OpCmovcc(a, 3); } static void OnCmovnbe(struct As *a, struct Slice s) { OpCmovcc(a, 7); } static void OnCmovnl(struct As *a, struct Slice s) { OpCmovcc(a, 13); } static void OnCmovnle(struct As *a, struct Slice s) { OpCmovcc(a, 15); } static void OnCmovno(struct As *a, struct Slice s) { OpCmovcc(a, 1); } static void OnCmovnp(struct As *a, struct Slice s) { OpCmovcc(a, 11); } static void OnCmovns(struct As *a, struct Slice s) { OpCmovcc(a, 9); } static void OnCmovnz(struct As *a, struct Slice s) { OpCmovcc(a, 5); } static void OnCmovo(struct As *a, struct Slice s) { OpCmovcc(a, 0); } static void OnCmovp(struct As *a, struct Slice s) { OpCmovcc(a, 10); } static void OnCmovs(struct As *a, struct Slice s) { OpCmovcc(a, 8); } static void OnCmovz(struct As *a, struct Slice s) { OpCmovcc(a, 4); } static void OnCmp(struct As *a, struct Slice s) { OpAlu(a, s, 7); } static void OnCmppd(struct As *a, struct Slice s) { OpSseIb(a, 0x660FC2); } static void OnCmpps(struct As *a, struct Slice s) { OpSseIb(a, 0x0FC2); } static void OnCmpsd(struct As *a, struct Slice s) { OpSseIb(a, 0xF20FC2); } static void OnCmpss(struct As *a, struct Slice s) { OpSseIb(a, 0xF30FC2); } static void OnComisd(struct As *a, struct Slice s) { OpSse(a, 0x660F2F); } static void OnComiss(struct As *a, struct Slice s) { OpSse(a, 0x0F2F); } static void OnCqto(struct As *a, struct Slice s) { EmitVarword(a, 0x4899); } static void OnCvtdq2pd(struct As *a, struct Slice s) { OpSse(a, 0xF30FE6); } static void OnCvtdq2ps(struct As *a, struct Slice s) { OpSse(a, 0xF5B); } static void OnCvtpd2dq(struct As *a, struct Slice s) { OpSse(a, 0xF20FE6); } static void OnCvtpd2ps(struct As *a, struct Slice s) { OpSse(a, 0x660F5A); } static void OnCvtps2dq(struct As *a, struct Slice s) { OpSse(a, 0x660F5B); } static void OnCvtps2pd(struct As *a, struct Slice s) { OpSse(a, 0x0F5A); } static void OnCvtsd2ss(struct As *a, struct Slice s) { OpSse(a, 0xF20F5A); } static void OnCvtsi2sd(struct As *a, struct Slice s) { OpSse(a, 0xF20F2A); } static void OnCvtsi2ss(struct As *a, struct Slice s) { OpSse(a, 0xF30F2A); } static void OnCvtss2sd(struct As *a, struct Slice s) { OpSse(a, 0xF30F5A); } static void OnCvttpd2dq(struct As *a, struct Slice s) { OpSse(a, 0x660FE6); } static void OnCvttps2dq(struct As *a, struct Slice s) { OpSse(a, 0xF30F5B); } static void OnCvttsd2si(struct As *a, struct Slice s) { OpSse(a, 0xF20F2C); } static void OnCvttss2si(struct As *a, struct Slice s) { OpSse(a, 0xF30F2C); } static void OnCwtd(struct As *a, struct Slice s) { EmitVarword(a, 0x6699); } static void OnCwtl(struct As *a, struct Slice s) { EmitByte(a, 0x98); } static void OnDec(struct As *a, struct Slice s) { OpBump(a, s, 1); } static void OnDiv(struct As *a, struct Slice s) { OpF6(a, s, 6); } static void OnDivpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5E); } static void OnDivps(struct As *a, struct Slice s) { OpSse(a, 0x0F5E); } static void OnDivsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5E); } static void OnDivss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5E); } static void OnDppd(struct As *a, struct Slice s) { OpSse(a, 0x660F3A41); } static void OnFabs(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E1); } static void OnFaddl(struct As *a, struct Slice s) { OpFpu1(a, 0xDC, 0); } static void OnFaddp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEC1); } static void OnFadds(struct As *a, struct Slice s) { OpFpu1(a, 0xD8, 0); } static void OnFchs(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E0); } static void OnFcmovb(struct As *a, struct Slice s) { OpFcom(a, 0xDAC0); } static void OnFcmovbe(struct As *a, struct Slice s) { OpFcom(a, 0xDAD0); } static void OnFcmove(struct As *a, struct Slice s) { OpFcom(a, 0xDAC8); } static void OnFcmovnb(struct As *a, struct Slice s) { OpFcom(a, 0xDBC0); } static void OnFcmovnbe(struct As *a, struct Slice s) { OpFcom(a, 0xDBD0); } static void OnFcmovne(struct As *a, struct Slice s) { OpFcom(a, 0xDBC8); } static void OnFcmovnu(struct As *a, struct Slice s) { OpFcom(a, 0xDBD8); } static void OnFcmovu(struct As *a, struct Slice s) { OpFcom(a, 0xDAD8); } static void OnFcomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBF0); } static void OnFcomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFF0); } static void OnFdivrp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEF9); } static void OnFildl(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 0); } static void OnFildll(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 5); } static void OnFildq(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 5); } static void OnFilds(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 0); } static void OnFistpq(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 7); } static void OnFisttpq(struct As *a, struct Slice s) { OpFpu1(a, 0xDD, 1); } static void OnFisttps(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 1); } static void OnFld(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 0); } static void OnFld1(struct As *a, struct Slice s) { EmitVarword(a, 0xd9e8); } static void OnFldcw(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 5); } static void OnFldl(struct As *a, struct Slice s) { OpFpu1(a, 0xDD, 0); } static void OnFldl2e(struct As *a, struct Slice s) { EmitVarword(a, 0xd9ea); } static void OnFldl2t(struct As *a, struct Slice s) { EmitVarword(a, 0xd9e9); } static void OnFldlg2(struct As *a, struct Slice s) { EmitVarword(a, 0xd9ec); } static void OnFldln2(struct As *a, struct Slice s) { EmitVarword(a, 0xd9ed); } static void OnFldpi(struct As *a, struct Slice s) { EmitVarword(a, 0xd9eb); } static void OnFlds(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 0); } static void OnFldt(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 5); } static void OnFldz(struct As *a, struct Slice s) { EmitVarword(a, 0xd9ee); } static void OnFmulp(struct As *a, struct Slice s) { EmitVarword(a, 0xdec9); } static void OnFnstcw(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 7); } static void OnFnstsw(struct As *a, struct Slice s) { OpFpu1(a, 0xDF, 4); } static void OnFstp(struct As *a, struct Slice s) { OpFpu1(a, 0xDD, 3); } static void OnFstpl(struct As *a, struct Slice s) { OpFpu1(a, 0xDD, 3); } static void OnFstps(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 3); } static void OnFstpt(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 7); } static void OnFsubrp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEE9); } static void OnFtst(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E4); } static void OnFucomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBE8); } static void OnFucomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFE8); } static void OnFwait(struct As *a, struct Slice s) { EmitByte(a, 0x9B); } static void OnFxam(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E5); } static void OnFxtract(struct As *a, struct Slice s) { EmitVarword(a, 0xD9F4); } static void OnHaddpd(struct As *a, struct Slice s) { OpSse(a, 0x660F7C); } static void OnHaddps(struct As *a, struct Slice s) { OpSse(a, 0xF20F7C); } static void OnHlt(struct As *a, struct Slice s) { EmitByte(a, 0xF4); } static void OnHsubpd(struct As *a, struct Slice s) { OpSse(a, 0x660F7D); } static void OnHsubps(struct As *a, struct Slice s) { OpSse(a, 0xF20F7D); } static void OnIdiv(struct As *a, struct Slice s) { OpF6(a, s, 7); } static void OnInc(struct As *a, struct Slice s) { OpBump(a, s, 0); } static void OnInt1(struct As *a, struct Slice s) { EmitByte(a, 0xF1); } static void OnInt3(struct As *a, struct Slice s) { EmitByte(a, 0xCC); } static void OnJb(struct As *a, struct Slice s) { OpJmp(a, 2); } static void OnJbe(struct As *a, struct Slice s) { OpJmp(a, 6); } static void OnJl(struct As *a, struct Slice s) { OpJmp(a, 12); } static void OnJle(struct As *a, struct Slice s) { OpJmp(a, 14); } static void OnJmp(struct As *a, struct Slice s) { OpJmp(a, -1); } static void OnJnb(struct As *a, struct Slice s) { OpJmp(a, 3); } static void OnJnbe(struct As *a, struct Slice s) { OpJmp(a, 7); } static void OnJnl(struct As *a, struct Slice s) { OpJmp(a, 13); } static void OnJnle(struct As *a, struct Slice s) { OpJmp(a, 15); } static void OnJno(struct As *a, struct Slice s) { OpJmp(a, 1); } static void OnJnp(struct As *a, struct Slice s) { OpJmp(a, 11); } static void OnJns(struct As *a, struct Slice s) { OpJmp(a, 9); } static void OnJnz(struct As *a, struct Slice s) { OpJmp(a, 5); } static void OnJo(struct As *a, struct Slice s) { OpJmp(a, 0); } static void OnJp(struct As *a, struct Slice s) { OpJmp(a, 10); } static void OnJs(struct As *a, struct Slice s) { OpJmp(a, 8); } static void OnJz(struct As *a, struct Slice s) { OpJmp(a, 4); } static void OnLeave(struct As *a, struct Slice s) { EmitByte(a, 0xC9); } static void OnLodsb(struct As *a, struct Slice s) { EmitByte(a, 0xAC); } static void OnLodsl(struct As *a, struct Slice s) { EmitByte(a, 0xAD); } static void OnLodsq(struct As *a, struct Slice s) { EmitVarword(a, 0x48AD); } static void OnLodsw(struct As *a, struct Slice s) { EmitVarword(a, 0x66AD); } static void OnMaxpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5F); } static void OnMaxps(struct As *a, struct Slice s) { OpSse(a, 0x0F5F); } static void OnMaxsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5F); } static void OnMaxss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5F); } static void OnMfence(struct As *a, struct Slice s) { EmitVarword(a, 0x0faef0); } static void OnMinpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5D); } static void OnMinps(struct As *a, struct Slice s) { OpSse(a, 0x0F5D); } static void OnMinsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5D); } static void OnMinss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5D); } static void OnMovmskpd(struct As *a, struct Slice s) { OpSse(a, 0x660F50); } static void OnMovmskps(struct As *a, struct Slice s) { OpSse(a, 0x0F50); } static void OnMovntdq(struct As *a, struct Slice s) { OpMovntdq(a); } static void OnMovsb(struct As *a, struct Slice s) { EmitByte(a, 0xA4); } static void OnMovsl(struct As *a, struct Slice s) { EmitByte(a, 0xA5); } static void OnMovsq(struct As *a, struct Slice s) { EmitVarword(a, 0x48A5); } static void OnMovsw(struct As *a, struct Slice s) { EmitVarword(a, 0x66A5); } static void OnMpsadbw(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A42); } static void OnMul(struct As *a, struct Slice s) { OpF6(a, s, 4); } static void OnMulpd(struct As *a, struct Slice s) { OpSse(a, 0x660F59); } static void OnMulps(struct As *a, struct Slice s) { OpSse(a, 0x0F59); } static void OnMulsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F59); } static void OnMulss(struct As *a, struct Slice s) { OpSse(a, 0xF30F59); } static void OnNeg(struct As *a, struct Slice s) { OpF6(a, s, 3); } static void OnNot(struct As *a, struct Slice s) { OpF6(a, s, 2); } static void OnOr(struct As *a, struct Slice s) { OpAlu(a, s, 1); } static void OnOrpd(struct As *a, struct Slice s) { OpSse(a, 0x660F56); } static void OnOrps(struct As *a, struct Slice s) { OpSse(a, 0x0F56); } static void OnPabsb(struct As *a, struct Slice s) { OpSse(a, 0x660F381C); } static void OnPabsd(struct As *a, struct Slice s) { OpSse(a, 0x660F381E); } static void OnPabsw(struct As *a, struct Slice s) { OpSse(a, 0x660F381D); } static void OnPackssdw(struct As *a, struct Slice s) { OpSse(a, 0x660F6B); } static void OnPacksswb(struct As *a, struct Slice s) { OpSse(a, 0x660F63); } static void OnPackusdw(struct As *a, struct Slice s) { OpSse(a, 0x660F382B); } static void OnPackuswb(struct As *a, struct Slice s) { OpSse(a, 0x660F67); } static void OnPaddb(struct As *a, struct Slice s) { OpSse(a, 0x660FFC); } static void OnPaddd(struct As *a, struct Slice s) { OpSse(a, 0x660FFE); } static void OnPaddq(struct As *a, struct Slice s) { OpSse(a, 0x660FD4); } static void OnPaddsb(struct As *a, struct Slice s) { OpSse(a, 0x660FEC); } static void OnPaddsw(struct As *a, struct Slice s) { OpSse(a, 0x660FED); } static void OnPaddusb(struct As *a, struct Slice s) { OpSse(a, 0x660FDC); } static void OnPaddusw(struct As *a, struct Slice s) { OpSse(a, 0x660FDD); } static void OnPaddw(struct As *a, struct Slice s) { OpSse(a, 0x660FFD); } static void OnPalignr(struct As *a, struct Slice s) { OpSse(a, 0x660F3A0F); } static void OnPand(struct As *a, struct Slice s) { OpSse(a, 0x660FDB); } static void OnPandn(struct As *a, struct Slice s) { OpSse(a, 0x660FDF); } static void OnPause(struct As *a, struct Slice s) { EmitVarword(a, 0xF390); } static void OnPavgb(struct As *a, struct Slice s) { OpSse(a, 0x660FE0); } static void OnPavgw(struct As *a, struct Slice s) { OpSse(a, 0x660FE3); } static void OnPblendvb(struct As *a, struct Slice s) { OpSse(a, 0x660F3810); } static void OnPblendw(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A0E); } static void OnPcmpeqb(struct As *a, struct Slice s) { OpSse(a, 0x660F74); } static void OnPcmpeqd(struct As *a, struct Slice s) { OpSse(a, 0x660F76); } static void OnPcmpeqq(struct As *a, struct Slice s) { OpSse(a, 0x660F3829); } static void OnPcmpeqw(struct As *a, struct Slice s) { OpSse(a, 0x660F75); } static void OnPcmpgtb(struct As *a, struct Slice s) { OpSse(a, 0x660F64); } static void OnPcmpgtd(struct As *a, struct Slice s) { OpSse(a, 0x660F66); } static void OnPcmpgtq(struct As *a, struct Slice s) { OpSse(a, 0x660F3837); } static void OnPcmpgtw(struct As *a, struct Slice s) { OpSse(a, 0x660F65); } static void OnPcmpistri(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A63); } static void OnPcmpistrm(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A62); } static void OnPhaddd(struct As *a, struct Slice s) { OpSse(a, 0x660F3802); } static void OnPhaddsw(struct As *a, struct Slice s) { OpSse(a, 0x660F3803); } static void OnPhaddw(struct As *a, struct Slice s) { OpSse(a, 0x660F3801); } static void OnPhminposuw(struct As *a, struct Slice s) { OpSse(a, 0x660F3841); } static void OnPhsubd(struct As *a, struct Slice s) { OpSse(a, 0x660F3806); } static void OnPhsubsw(struct As *a, struct Slice s) { OpSse(a, 0x660F3807); } static void OnPhsubw(struct As *a, struct Slice s) { OpSse(a, 0x660F3805); } static void OnPmaddubsw(struct As *a, struct Slice s) { OpSse(a, 0x660F3804); } static void OnPmaddwd(struct As *a, struct Slice s) { OpSse(a, 0x660FF5); } static void OnPmaxsb(struct As *a, struct Slice s) { OpSse(a, 0x660F383C); } static void OnPmaxsd(struct As *a, struct Slice s) { OpSse(a, 0x660F383D); } static void OnPmaxsw(struct As *a, struct Slice s) { OpSse(a, 0x660FEE); } static void OnPmaxub(struct As *a, struct Slice s) { OpSse(a, 0x660FDE); } static void OnPmaxud(struct As *a, struct Slice s) { OpSse(a, 0x660F383F); } static void OnPmaxuw(struct As *a, struct Slice s) { OpSse(a, 0x660F383E); } static void OnPminsb(struct As *a, struct Slice s) { OpSse(a, 0x660F3838); } static void OnPminsd(struct As *a, struct Slice s) { OpSse(a, 0x660F3839); } static void OnPminsw(struct As *a, struct Slice s) { OpSse(a, 0x660FEA); } static void OnPminub(struct As *a, struct Slice s) { OpSse(a, 0x660FDA); } static void OnPminud(struct As *a, struct Slice s) { OpSse(a, 0x660F383B); } static void OnPminuw(struct As *a, struct Slice s) { OpSse(a, 0x660F383A); } static void OnPmovmskb(struct As *a, struct Slice s) { OpSse(a, 0x660FD7); } static void OnPmuldq(struct As *a, struct Slice s) { OpSse(a, 0x660F3828); } static void OnPmulhrsw(struct As *a, struct Slice s) { OpSse(a, 0x660F380B); } static void OnPmulhuw(struct As *a, struct Slice s) { OpSse(a, 0x660FE4); } static void OnPmulhw(struct As *a, struct Slice s) { OpSse(a, 0x660FE5); } static void OnPmulld(struct As *a, struct Slice s) { OpSse(a, 0x660F3840); } static void OnPmullw(struct As *a, struct Slice s) { OpSse(a, 0x660FD5); } static void OnPmuludq(struct As *a, struct Slice s) { OpSse(a, 0x660FF4); } static void OnPopcnt(struct As *a, struct Slice s) { OpBit(a, 0xF30FB8); } static void OnPor(struct As *a, struct Slice s) { OpSse(a, 0x660FEB); } static void OnPsadbw(struct As *a, struct Slice s) { OpSse(a, 0x660FF6); } static void OnPshufb(struct As *a, struct Slice s) { OpSse(a, 0x660F3800); } static void OnPshufd(struct As *a, struct Slice s) { OpSseIb(a, 0x660F70); } static void OnPshufhw(struct As *a, struct Slice s) { OpSseIb(a, 0xF30F70); } static void OnPshuflw(struct As *a, struct Slice s) { OpSseIb(a, 0xF20F70); } static void OnPsignb(struct As *a, struct Slice s) { OpSse(a, 0x660F3808); } static void OnPsignd(struct As *a, struct Slice s) { OpSse(a, 0x660F380A); } static void OnPsignw(struct As *a, struct Slice s) { OpSse(a, 0x660F3809); } static void OnPslld(struct As *a, struct Slice s) { OpSse(a, 0x660FF2); } static void OnPsllq(struct As *a, struct Slice s) { OpSse(a, 0x660FF3); } static void OnPsllw(struct As *a, struct Slice s) { OpSse(a, 0x660FF1); } static void OnPsrad(struct As *a, struct Slice s) { OpSse(a, 0x660FE2); } static void OnPsraw(struct As *a, struct Slice s) { OpSse(a, 0x660FE1); } static void OnPsrld(struct As *a, struct Slice s) { OpSse(a, 0x660FD2); } static void OnPsrlq(struct As *a, struct Slice s) { OpSse(a, 0x660FD3); } static void OnPsrlw(struct As *a, struct Slice s) { OpSse(a, 0x660FD1); } static void OnPsubb(struct As *a, struct Slice s) { OpSse(a, 0x660FF8); } static void OnPsubd(struct As *a, struct Slice s) { OpSse(a, 0x660FFA); } static void OnPsubq(struct As *a, struct Slice s) { OpSse(a, 0x660FFB); } static void OnPsubsb(struct As *a, struct Slice s) { OpSse(a, 0x660FE8); } static void OnPsubsw(struct As *a, struct Slice s) { OpSse(a, 0x660FE9); } static void OnPsubusb(struct As *a, struct Slice s) { OpSse(a, 0x660FD8); } static void OnPsubusw(struct As *a, struct Slice s) { OpSse(a, 0x660FD9); } static void OnPsubw(struct As *a, struct Slice s) { OpSse(a, 0x660FF9); } static void OnPtest(struct As *a, struct Slice s) { OpSse(a, 0x660F3817); } static void OnPunpckhbw(struct As *a, struct Slice s) { OpSse(a, 0x660F68); } static void OnPunpckhdq(struct As *a, struct Slice s) { OpSse(a, 0x660F6A); } static void OnPunpckhqdq(struct As *a, struct Slice s) { OpSse(a, 0x660F6D); } static void OnPunpckhwd(struct As *a, struct Slice s) { OpSse(a, 0x660F69); } static void OnPunpcklbw(struct As *a, struct Slice s) { OpSse(a, 0x660F60); } static void OnPunpckldq(struct As *a, struct Slice s) { OpSse(a, 0x660F62); } static void OnPunpcklqdq(struct As *a, struct Slice s) { OpSse(a, 0x660F6C); } static void OnPunpcklwd(struct As *a, struct Slice s) { OpSse(a, 0x660F61); } static void OnPxor(struct As *a, struct Slice s) { OpSse(a, 0x660FEF); } static void OnRcl(struct As *a, struct Slice s) { OpBsu(a, s, 2); } static void OnRcpps(struct As *a, struct Slice s) { OpSse(a, 0x0F53); } static void OnRcpss(struct As *a, struct Slice s) { OpSse(a, 0xF30F53); } static void OnRcr(struct As *a, struct Slice s) { OpBsu(a, s, 3); } static void OnRdtsc(struct As *a, struct Slice s) { EmitVarword(a, 0x0f31); } static void OnRdtscp(struct As *a, struct Slice s) { EmitVarword(a, 0x0f01f9); } static void OnRol(struct As *a, struct Slice s) { OpBsu(a, s, 0); } static void OnRor(struct As *a, struct Slice s) { OpBsu(a, s, 1); } static void OnRoundsd(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A0B); } static void OnRoundss(struct As *a, struct Slice s) { OpSseIb(a, 0x660F3A0A); } static void OnRsqrtps(struct As *a, struct Slice s) { OpSse(a, 0x0F52); } static void OnRsqrtss(struct As *a, struct Slice s) { OpSse(a, 0xF30F52); } static void OnSal(struct As *a, struct Slice s) { OpBsu(a, s, 6); } static void OnSar(struct As *a, struct Slice s) { OpBsu(a, s, 7); } static void OnSbb(struct As *a, struct Slice s) { OpAlu(a, s, 3); } static void OnSetb(struct As *a, struct Slice s) { OpSetcc(a, 2); } static void OnSetbe(struct As *a, struct Slice s) { OpSetcc(a, 6); } static void OnSetl(struct As *a, struct Slice s) { OpSetcc(a, 12); } static void OnSetle(struct As *a, struct Slice s) { OpSetcc(a, 14); } static void OnSetnb(struct As *a, struct Slice s) { OpSetcc(a, 3); } static void OnSetnbe(struct As *a, struct Slice s) { OpSetcc(a, 7); } static void OnSetnl(struct As *a, struct Slice s) { OpSetcc(a, 13); } static void OnSetnle(struct As *a, struct Slice s) { OpSetcc(a, 15); } static void OnSetno(struct As *a, struct Slice s) { OpSetcc(a, 1); } static void OnSetnp(struct As *a, struct Slice s) { OpSetcc(a, 11); } static void OnSetns(struct As *a, struct Slice s) { OpSetcc(a, 9); } static void OnSetnz(struct As *a, struct Slice s) { OpSetcc(a, 5); } static void OnSeto(struct As *a, struct Slice s) { OpSetcc(a, 0); } static void OnSetp(struct As *a, struct Slice s) { OpSetcc(a, 10); } static void OnSets(struct As *a, struct Slice s) { OpSetcc(a, 8); } static void OnSetz(struct As *a, struct Slice s) { OpSetcc(a, 4); } static void OnSfence(struct As *a, struct Slice s) { EmitVarword(a, 0x0faef8); } static void OnShl(struct As *a, struct Slice s) { OpBsu(a, s, 4); } static void OnShr(struct As *a, struct Slice s) { OpBsu(a, s, 5); } static void OnShufpd(struct As *a, struct Slice s) { OpSseIb(a, 0x660FC6); } static void OnShufps(struct As *a, struct Slice s) { OpSseIb(a, 0x0FC6); } static void OnSqrtpd(struct As *a, struct Slice s) { OpSse(a, 0x660F51); } static void OnSqrtps(struct As *a, struct Slice s) { OpSse(a, 0x0F51); } static void OnSqrtsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F51); } static void OnSqrtss(struct As *a, struct Slice s) { OpSse(a, 0xF30F51); } static void OnStc(struct As *a, struct Slice s) { EmitByte(a, 0xF9); } static void OnStd(struct As *a, struct Slice s) { EmitByte(a, 0xFD); } static void OnSti(struct As *a, struct Slice s) { EmitByte(a, 0xFB); } static void OnStosb(struct As *a, struct Slice s) { EmitByte(a, 0xAA); } static void OnStosl(struct As *a, struct Slice s) { EmitByte(a, 0xAB); } static void OnStosq(struct As *a, struct Slice s) { EmitVarword(a, 0x48AB); } static void OnStosw(struct As *a, struct Slice s) { EmitVarword(a, 0x66AB); } static void OnSub(struct As *a, struct Slice s) { OpAlu(a, s, 5); } static void OnSubpd(struct As *a, struct Slice s) { OpSse(a, 0x660F5C); } static void OnSubps(struct As *a, struct Slice s) { OpSse(a, 0x0F5C); } static void OnSubsd(struct As *a, struct Slice s) { OpSse(a, 0xF20F5C); } static void OnSubss(struct As *a, struct Slice s) { OpSse(a, 0xF30F5C); } static void OnSyscall(struct As *a, struct Slice s) { EmitVarword(a, 0x0F05); } static void OnUcomisd(struct As *a, struct Slice s) { OpSse(a, 0x660F2E); } static void OnUcomiss(struct As *a, struct Slice s) { OpSse(a, 0x0F2E); } static void OnUd2(struct As *a, struct Slice s) { EmitVarword(a, 0x0F0B); } static void OnUnpckhpd(struct As *a, struct Slice s) { OpSse(a, 0x660F15); } static void OnUnpcklpd(struct As *a, struct Slice s) { OpSse(a, 0x660F14); } static void OnXadd(struct As *a, struct Slice s) { OpXadd(a); } static void OnXor(struct As *a, struct Slice s) { OpAlu(a, s, 6); } static void OnXorpd(struct As *a, struct Slice s) { OpSse(a, 0x660F57); } static void OnXorps(struct As *a, struct Slice s) { OpSse(a, 0x0F57); } // clang-format on static const struct Directive8 { char s[8]; void (*f)(struct As *, struct Slice); } kDirective8[] = { {".abort", OnAbort}, // {".align", OnAlign}, // {".ascii", OnAscii}, // {".asciz", OnAsciz}, // {".balign", OnAlign}, // {".bss", OnBss}, // {".byte", OnByte}, // {".comm", OnComm}, // {".data", OnData}, // {".double", OnDouble}, // {".equ", OnEqu}, // {".err", OnErr}, // {".error", OnError}, // {".file", OnFile}, // {".float", OnFloat}, // {".float80", OnFloat80}, // {".global", OnGlobal}, // {".globl", OnGlobal}, // {".hidden", OnHidden}, // {".ident", OnIdent}, // {".incbin", OnIncbin}, // {".ldbl", OnLdbl}, // {".loc", OnLoc}, // {".local", OnLocal}, // {".long", OnLong}, // {".octa", OnOcta}, // {".quad", OnQuad}, // {".section", OnSection}, // {".short", OnWord}, // {".size", OnSize}, // {".sleb128", OnSleb128}, // {".space", OnSpace}, // {".text", OnText}, // {".type", OnType}, // {".uleb128", OnUleb128}, // {".warning", OnWarning}, // {".weak", OnWeak}, // {".word", OnWord}, // {".zero", OnZero}, // {".zleb128", OnZleb128}, // {"adc", OnAdc}, // {"adcb", OnAdc}, // {"adcl", OnAdc}, // {"adcq", OnAdc}, // {"adcw", OnAdc}, // {"add", OnAdd}, // {"addb", OnAdd}, // {"addl", OnAdd}, // {"addpd", OnAddpd}, // {"addps", OnAddps}, // {"addq", OnAdd}, // {"addsd", OnAddsd}, // {"addss", OnAddss}, // {"addsubpd", OnAddsubpd}, // {"addsubps", OnAddsubps}, // {"addw", OnAdd}, // {"and", OnAnd}, // {"andb", OnAnd}, // {"andl", OnAnd}, // {"andnpd", OnAndnpd}, // {"andnps", OnAndnps}, // {"andpd", OnAndpd}, // {"andps", OnAndps}, // {"andq", OnAnd}, // {"andw", OnAnd}, // {"blendpd", OnBlendpd}, // {"blendvpd", OnBlendvpd}, // {"bsf", OnBsf}, // {"bsr", OnBsr}, // {"bswap", OnBswap}, // {"call", OnCall}, // {"callq", OnCall}, // {"cbtw", OnCbtw}, // {"cbw", OnCbtw}, // {"cdq", OnCltd}, // {"cdqe", OnCltq}, // {"clc", OnClc}, // {"cld", OnCld}, // {"cli", OnCli}, // {"cltd", OnCltd}, // {"cltq", OnCltq}, // {"cmc", OnCmc}, // {"cmova", OnCmovnbe}, // {"cmovae", OnCmovnb}, // {"cmovb", OnCmovb}, // {"cmovbe", OnCmovbe}, // {"cmovc", OnCmovb}, // {"cmove", OnCmovz}, // {"cmovg", OnCmovnle}, // {"cmovge", OnCmovnl}, // {"cmovl", OnCmovl}, // {"cmovle", OnCmovle}, // {"cmovna", OnCmovbe}, // {"cmovnae", OnCmovb}, // {"cmovnb", OnCmovnb}, // {"cmovnbe", OnCmovnbe}, // {"cmovnc", OnCmovnb}, // {"cmovne", OnCmovnz}, // {"cmovng", OnCmovle}, // {"cmovnge", OnCmovl}, // {"cmovnl", OnCmovnl}, // {"cmovnle", OnCmovnle}, // {"cmovno", OnCmovno}, // {"cmovnp", OnCmovnp}, // {"cmovns", OnCmovns}, // {"cmovnz", OnCmovnz}, // {"cmovo", OnCmovo}, // {"cmovp", OnCmovp}, // {"cmovpe", OnCmovp}, // {"cmovpo", OnCmovnp}, // {"cmovs", OnCmovs}, // {"cmovz", OnCmovz}, // {"cmp", OnCmp}, // {"cmpb", OnCmp}, // {"cmpl", OnCmp}, // {"cmppd", OnCmppd}, // {"cmpps", OnCmpps}, // {"cmpq", OnCmp}, // {"cmpsd", OnCmpsd}, // {"cmpss", OnCmpss}, // {"cmpw", OnCmp}, // {"cmpxchg", OnCmpxchg}, // {"comisd", OnComisd}, // {"comiss", OnComiss}, // {"cqo", OnCqto}, // {"cqto", OnCqto}, // {"cvtdq2pd", OnCvtdq2pd}, // {"cvtdq2ps", OnCvtdq2ps}, // {"cvtpd2dq", OnCvtpd2dq}, // {"cvtpd2ps", OnCvtpd2ps}, // {"cvtps2dq", OnCvtps2dq}, // {"cvtps2pd", OnCvtps2pd}, // {"cvtsd2ss", OnCvtsd2ss}, // {"cvtsd2ss", OnCvtsd2ss}, // {"cvtsi2sd", OnCvtsi2sd}, // {"cvtsi2sd", OnCvtsi2sd}, // {"cvtsi2ss", OnCvtsi2ss}, // {"cvtsi2ss", OnCvtsi2ss}, // {"cvtss2sd", OnCvtss2sd}, // {"cwd", OnCwtd}, // {"cwde", OnCwtl}, // {"cwtd", OnCwtd}, // {"cwtl", OnCwtl}, // {"dec", OnDec}, // {"decb", OnDec}, // {"decl", OnDec}, // {"decq", OnDec}, // {"decw", OnDec}, // {"div", OnDiv}, // {"divpd", OnDivpd}, // {"divps", OnDivps}, // {"divsd", OnDivsd}, // {"divss", OnDivss}, // {"dppd", OnDppd}, // {"fabs", OnFabs}, // {"faddl", OnFaddl}, // {"faddp", OnFaddp}, // {"fadds", OnFadds}, // {"fchs", OnFchs}, // {"fcmovb", OnFcmovb}, // {"fcmovbe", OnFcmovbe}, // {"fcmove", OnFcmove}, // {"fcmovnb", OnFcmovnb}, // {"fcmovnbe", OnFcmovnbe}, // {"fcmovne", OnFcmovne}, // {"fcmovnu", OnFcmovnu}, // {"fcmovu", OnFcmovu}, // {"fcomi", OnFcomi}, // {"fcomip", OnFcomip}, // {"fdivrp", OnFdivrp}, // {"fildl", OnFildl}, // {"fildll", OnFildll}, // {"fildq", OnFildq}, // {"filds", OnFilds}, // {"fistpll", OnFistpq}, // {"fistpq", OnFistpq}, // {"fisttpll", OnFisttpq}, // {"fisttpq", OnFisttpq}, // {"fisttps", OnFisttps}, // {"fld", OnFld}, // {"fld1", OnFld1}, // {"fldcw", OnFldcw}, // {"fldl", OnFldl}, // {"fldl2e", OnFldl2e}, // {"fldl2t", OnFldl2t}, // {"fldlg2", OnFldlg2}, // {"fldln2", OnFldln2}, // {"fldpi", OnFldpi}, // {"flds", OnFlds}, // {"fldt", OnFldt}, // {"fldz", OnFldz}, // {"fmulp", OnFmulp}, // {"fnstcw", OnFnstcw}, // {"fnstsw", OnFnstsw}, // {"fstp", OnFstp}, // {"fstpl", OnFstpl}, // {"fstps", OnFstps}, // {"fstpt", OnFstpt}, // {"fsubrp", OnFsubrp}, // {"ftst", OnFtst}, // {"fucomi", OnFucomi}, // {"fucomip", OnFucomip}, // {"fwait", OnFwait}, // {"fxam", OnFxam}, // {"fxch", OnFxch}, // {"fxtract", OnFxtract}, // {"haddpd", OnHaddpd}, // {"haddps", OnHaddps}, // {"hlt", OnHlt}, // {"hsubpd", OnHsubpd}, // {"hsubps", OnHsubps}, // {"icebp", OnInt1}, // {"idiv", OnIdiv}, // {"imul", OnImul}, // {"inc", OnInc}, // {"incb", OnInc}, // {"incl", OnInc}, // {"incq", OnInc}, // {"incw", OnInc}, // {"int1", OnInt1}, // {"int3", OnInt3}, // {"ja", OnJnbe}, // {"jae", OnJnb}, // {"jb", OnJb}, // {"jbe", OnJbe}, // {"jc", OnJb}, // {"je", OnJz}, // {"jg", OnJnle}, // {"jge", OnJnl}, // {"jl", OnJl}, // {"jle", OnJle}, // {"jmp", OnJmp}, // {"jmpq", OnJmp}, // {"jna", OnJbe}, // {"jnae", OnJb}, // {"jnb", OnJnb}, // {"jnbe", OnJnbe}, // {"jnc", OnJnb}, // {"jne", OnJnz}, // {"jng", OnJle}, // {"jnge", OnJl}, // {"jnl", OnJnl}, // {"jnle", OnJnle}, // {"jno", OnJno}, // {"jnp", OnJnp}, // {"jns", OnJns}, // {"jnz", OnJnz}, // {"jo", OnJo}, // {"jp", OnJp}, // {"jpe", OnJp}, // {"jpo", OnJnp}, // {"js", OnJs}, // {"jz", OnJz}, // {"lar", OnLar}, // {"lea", OnLea}, // {"leave", OnLeave}, // {"lodsb", OnLodsb}, // {"lodsl", OnLodsl}, // {"lodsq", OnLodsq}, // {"lodsw", OnLodsw}, // {"lsl", OnLsl}, // {"maxpd", OnMaxpd}, // {"maxps", OnMaxps}, // {"maxsd", OnMaxsd}, // {"maxss", OnMaxss}, // {"mfence", OnMfence}, // {"minpd", OnMinpd}, // {"minps", OnMinps}, // {"minsd", OnMinsd}, // {"minss", OnMinss}, // {"mov", OnMov}, // {"movabs", OnMov}, // {"movapd", OnMovapd}, // {"movaps", OnMovaps}, // {"movb", OnMov}, // {"movd", OnMovd}, // {"movdqa", OnMovdqa}, // {"movdqa", OnMovdqa}, // {"movdqu", OnMovdqu}, // {"movdqu", OnMovdqu}, // {"movl", OnMov}, // {"movmskpd", OnMovmskpd}, // {"movmskps", OnMovmskps}, // {"movq", OnMovq}, // {"movsb", OnMovsb}, // {"movsbl", OnMovsbwx}, // {"movsbq", OnMovsbwx}, // {"movsbw", OnMovsbwx}, // {"movsd", OnMovsd}, // {"movsd", OnMovsd}, // {"movsl", OnMovsl}, // {"movslq", OnMovslq}, // {"movsq", OnMovsq}, // {"movss", OnMovss}, // {"movss", OnMovss}, // {"movsw", OnMovsw}, // {"movswl", OnMovsbwx}, // {"movswq", OnMovsbwx}, // {"movupd", OnMovupd}, // {"movups", OnMovups}, // {"movw", OnMov}, // {"movzbl", OnMovzbwx}, // {"movzbq", OnMovzbwx}, // {"movzbw", OnMovzbwx}, // {"movzwl", OnMovzbwx}, // {"movzwq", OnMovzbwx}, // {"mpsadbw", OnMpsadbw}, // {"mul", OnMul}, // {"mulpd", OnMulpd}, // {"mulps", OnMulps}, // {"mulsd", OnMulsd}, // {"mulss", OnMulss}, // {"neg", OnNeg}, // {"negb", OnNeg}, // {"negl", OnNeg}, // {"negq", OnNeg}, // {"negw", OnNeg}, // {"nop", OnNop}, // {"nopb", OnNop}, // {"nopl", OnNop}, // {"nopq", OnNop}, // {"nopw", OnNop}, // {"not", OnNot}, // {"notb", OnNot}, // {"notl", OnNot}, // {"notq", OnNot}, // {"notw", OnNot}, // {"or", OnOr}, // {"orb", OnOr}, // {"orl", OnOr}, // {"orpd", OnOrpd}, // {"orps", OnOrps}, // {"orq", OnOr}, // {"orw", OnOr}, // {"pabsb", OnPabsb}, // {"pabsd", OnPabsd}, // {"pabsw", OnPabsw}, // {"packssdw", OnPackssdw}, // {"packsswb", OnPacksswb}, // {"packusdw", OnPackusdw}, // {"packuswb", OnPackuswb}, // {"paddb", OnPaddb}, // {"paddd", OnPaddd}, // {"paddq", OnPaddq}, // {"paddsb", OnPaddsb}, // {"paddsw", OnPaddsw}, // {"paddusb", OnPaddusb}, // {"paddusw", OnPaddusw}, // {"paddw", OnPaddw}, // {"palignr", OnPalignr}, // {"pand", OnPand}, // {"pandn", OnPandn}, // {"pause", OnPause}, // {"pavgb", OnPavgb}, // {"pavgw", OnPavgw}, // {"pblendvb", OnPblendvb}, // {"pblendw", OnPblendw}, // {"pcmpeqb", OnPcmpeqb}, // {"pcmpeqd", OnPcmpeqd}, // {"pcmpeqq", OnPcmpeqq}, // {"pcmpeqw", OnPcmpeqw}, // {"pcmpgtb", OnPcmpgtb}, // {"pcmpgtd", OnPcmpgtd}, // {"pcmpgtq", OnPcmpgtq}, // {"pcmpgtw", OnPcmpgtw}, // {"phaddd", OnPhaddd}, // {"phaddsw", OnPhaddsw}, // {"phaddw", OnPhaddw}, // {"phsubd", OnPhsubd}, // {"phsubsw", OnPhsubsw}, // {"phsubw", OnPhsubw}, // {"pmaddwd", OnPmaddwd}, // {"pmaxsb", OnPmaxsb}, // {"pmaxsd", OnPmaxsd}, // {"pmaxsw", OnPmaxsw}, // {"pmaxub", OnPmaxub}, // {"pmaxud", OnPmaxud}, // {"pmaxuw", OnPmaxuw}, // {"pminsb", OnPminsb}, // {"pminsd", OnPminsd}, // {"pminsw", OnPminsw}, // {"pminub", OnPminub}, // {"pminud", OnPminud}, // {"pminuw", OnPminuw}, // {"pmovmskb", OnPmovmskb}, // {"pmuldq", OnPmuldq}, // {"pmulhrsw", OnPmulhrsw}, // {"pmulhuw", OnPmulhuw}, // {"pmulhw", OnPmulhw}, // {"pmulld", OnPmulld}, // {"pmullw", OnPmullw}, // {"pmuludq", OnPmuludq}, // {"pop", OnPop}, // {"popcnt", OnPopcnt}, // {"por", OnPor}, // {"psadbw", OnPsadbw}, // {"pshufb", OnPshufb}, // {"pshufd", OnPshufd}, // {"pshufhw", OnPshufhw}, // {"pshuflw", OnPshuflw}, // {"psignb", OnPsignb}, // {"psignd", OnPsignd}, // {"psignw", OnPsignw}, // {"pslld", OnPslld}, // {"psllq", OnPsllq}, // {"psllw", OnPsllw}, // {"psrad", OnPsrad}, // {"psraw", OnPsraw}, // {"psrld", OnPsrld}, // {"psrlq", OnPsrlq}, // {"psrlw", OnPsrlw}, // {"psubb", OnPsubb}, // {"psubd", OnPsubd}, // {"psubq", OnPsubq}, // {"psubsb", OnPsubsb}, // {"psubsw", OnPsubsw}, // {"psubusb", OnPsubusb}, // {"psubusw", OnPsubusw}, // {"psubw", OnPsubw}, // {"ptest", OnPtest}, // {"push", OnPush}, // {"pxor", OnPxor}, // {"rcl", OnRcl}, // {"rclb", OnRcl}, // {"rcll", OnRcl}, // {"rclq", OnRcl}, // {"rclw", OnRcl}, // {"rcpps", OnRcpps}, // {"rcpss", OnRcpss}, // {"rcr", OnRcr}, // {"rcrb", OnRcr}, // {"rcrl", OnRcr}, // {"rcrq", OnRcr}, // {"rcrw", OnRcr}, // {"rdpid", OnRdpid}, // {"rdtsc", OnRdtsc}, // {"rdtscp", OnRdtscp}, // {"ret", OnRet}, // {"rol", OnRol}, // {"rolb", OnRol}, // {"roll", OnRol}, // {"rolq", OnRol}, // {"rolw", OnRol}, // {"ror", OnRor}, // {"rorb", OnRor}, // {"rorl", OnRor}, // {"rorq", OnRor}, // {"rorw", OnRor}, // {"roundsd", OnRoundsd}, // {"roundss", OnRoundss}, // {"rsqrtps", OnRsqrtps}, // {"rsqrtss", OnRsqrtss}, // {"sal", OnSal}, // {"salb", OnSal}, // {"sall", OnSal}, // {"salq", OnSal}, // {"salw", OnSal}, // {"sar", OnSar}, // {"sarb", OnSar}, // {"sarl", OnSar}, // {"sarq", OnSar}, // {"sarw", OnSar}, // {"sbb", OnSbb}, // {"sbbb", OnSbb}, // {"sbbl", OnSbb}, // {"sbbq", OnSbb}, // {"sbbw", OnSbb}, // {"seta", OnSetnbe}, // {"setae", OnSetnb}, // {"setb", OnSetb}, // {"setbe", OnSetbe}, // {"setc", OnSetb}, // {"sete", OnSetz}, // {"setg", OnSetnle}, // {"setge", OnSetnl}, // {"setl", OnSetl}, // {"setle", OnSetle}, // {"setna", OnSetbe}, // {"setnae", OnSetb}, // {"setnb", OnSetnb}, // {"setnbe", OnSetnbe}, // {"setnc", OnSetnb}, // {"setne", OnSetnz}, // {"setng", OnSetle}, // {"setnge", OnSetl}, // {"setnl", OnSetnl}, // {"setnle", OnSetnle}, // {"setno", OnSetno}, // {"setnp", OnSetnp}, // {"setns", OnSetns}, // {"setnz", OnSetnz}, // {"seto", OnSeto}, // {"setp", OnSetp}, // {"setpe", OnSetp}, // {"setpo", OnSetnp}, // {"sets", OnSets}, // {"setz", OnSetz}, // {"sfence", OnSfence}, // {"shl", OnShl}, // {"shlb", OnShl}, // {"shld", OnShld}, // {"shll", OnShl}, // {"shlq", OnShl}, // {"shlw", OnShl}, // {"shr", OnShr}, // {"shrb", OnShr}, // {"shrd", OnShrd}, // {"shrl", OnShr}, // {"shrq", OnShr}, // {"shrw", OnShr}, // {"shufpd", OnShufpd}, // {"shufps", OnShufps}, // {"sqrtpd", OnSqrtpd}, // {"sqrtps", OnSqrtps}, // {"sqrtsd", OnSqrtsd}, // {"sqrtss", OnSqrtss}, // {"stc", OnStc}, // {"std", OnStd}, // {"sti", OnSti}, // {"stosb", OnStosb}, // {"stosl", OnStosl}, // {"stosq", OnStosq}, // {"stosw", OnStosw}, // {"sub", OnSub}, // {"subb", OnSub}, // {"subl", OnSub}, // {"subpd", OnSubpd}, // {"subps", OnSubps}, // {"subq", OnSub}, // {"subsd", OnSubsd}, // {"subss", OnSubss}, // {"subw", OnSub}, // {"syscall", OnSyscall}, // {"test", OnTest}, // {"testb", OnTest}, // {"testl", OnTest}, // {"testq", OnTest}, // {"testw", OnTest}, // {"ucomisd", OnUcomisd}, // {"ucomiss", OnUcomiss}, // {"ud2", OnUd2}, // {"unpckhpd", OnUnpckhpd}, // {"unpcklpd", OnUnpcklpd}, // {"wait", OnFwait}, // {"xadd", OnXadd}, // {"xchg", OnXchg}, // {"xor", OnXor}, // {"xorb", OnXor}, // {"xorl", OnXor}, // {"xorpd", OnXorpd}, // {"xorps", OnXorps}, // {"xorq", OnXor}, // {"xorw", OnXor}, // }; static const struct Directive16 { char s[16]; void (*f)(struct As *, struct Slice); } kDirective16[] = { {".internal", OnInternal}, // {".popsection", OnPopsection}, // {".previous", OnPrevious}, // {".protected", OnProtected}, // {".pushsection", OnPushsection}, // {"cvtsd2ssl", OnCvtsd2ss}, // {"cvtsd2ssq", OnCvtsd2ss}, // {"cvtsi2sdl", OnCvtsi2sd}, // {"cvtsi2sdq", OnCvtsi2sd}, // {"cvtsi2sdq", OnCvtsi2sd}, // {"cvtsi2ssl", OnCvtsi2ss}, // {"cvtsi2ssq", OnCvtsi2ss}, // {"cvttpd2dq", OnCvttpd2dq}, // {"cvttps2dq", OnCvttps2dq}, // {"cvttsd2si", OnCvttsd2si}, // {"cvttsd2sil", OnCvttsd2si}, // {"cvttsd2siq", OnCvttsd2si}, // {"cvttss2si", OnCvttss2si}, // {"cvttss2sil", OnCvttss2si}, // {"cvttss2siq", OnCvttss2si}, // {"movntdq", OnMovntdq}, // {"pcmpistri", OnPcmpistri}, // {"pcmpistrm", OnPcmpistrm}, // {"phminposuw", OnPhminposuw}, // {"pmaddubsw", OnPmaddubsw}, // {"punpckhbw", OnPunpckhbw}, // {"punpckhdq", OnPunpckhdq}, // {"punpckhqdq", OnPunpckhqdq}, // {"punpckhwd", OnPunpckhwd}, // {"punpcklbw", OnPunpcklbw}, // {"punpckldq", OnPunpckldq}, // {"punpcklqdq", OnPunpcklqdq}, // {"punpcklwd", OnPunpcklwd}, // }; static bool OnDirective8(struct As *a, struct Slice s) { int m, l, r; uint64_t x, y; if (s.n && s.n <= 8) { x = MakeKey64(s.p, s.n); l = 0; r = ARRAYLEN(kDirective8) - 1; while (l <= r) { m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ64BE(kDirective8[m].s); if (x < y) { r = m - 1; } else if (x > y) { l = m + 1; } else { kDirective8[m].f(a, s); return true; } } } return false; } static bool OnDirective16(struct As *a, struct Slice s) { int m, l, r; unsigned __int128 x, y; if (s.n && s.n <= 16) { x = MakeKey128(s.p, s.n); l = 0; r = ARRAYLEN(kDirective16) - 1; while (l <= r) { m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2) y = READ128BE(kDirective16[m].s); if (x < y) { r = m - 1; } else if (x > y) { l = m + 1; } else { kDirective16[m].f(a, s); return true; } } } return false; } static void OnDirective(struct As *a) { struct Slice s; for (;;) { s = GetSlice(a); if (Prefix(a, s.p, s.n)) { if (IsSemicolon(a)) { return; } } else { break; } } if (!OnDirective8(a, s)) { if (!OnDirective16(a, s)) { Fail(a, "unexpected op: %.*s", s.n, s.p); } } ConsumePunct(a, ';'); } static void Assemble(struct As *a) { while (a->i < a->things.n) { if (IsSemicolon(a)) { ++a->i; continue; } switch (a->things.p[a->i].t) { case TT_SLICE: if (IsPunct(a, a->i + 1, ':')) { OnSymbol(a, a->things.p[a->i].i); } else { OnDirective(a); } break; case TT_INT: if (IsPunct(a, a->i + 1, ':')) { OnLocalLabel(a, a->ints.p[a->things.p[a->i].i]); break; } Fail(a, "unexpected token"); default: Fail(a, "unexpected token"); } } } static int FindLabelForward(struct As *a, int id) { int i; for (i = 0; i < a->labels.n; ++i) { if (a->labels.p[i].id == id && a->labels.p[i].tok > a->i) { return a->labels.p[i].symbol; } } Fail(a, "label not found"); } static int FindLabelBackward(struct As *a, int id) { int i; for (i = a->labels.n; i--;) { if (a->labels.p[i].id == id && a->labels.p[i].tok < a->i) { return a->labels.p[i].symbol; } } Fail(a, "label not found"); } static int ResolveSymbol(struct As *a, int i) { switch (a->things.p[i].t) { case TT_SLICE: return GetSymbol(a, a->things.p[i].i); case TT_BACKWARD: return FindLabelBackward(a, a->ints.p[a->things.p[i].i]); case TT_FORWARD: return FindLabelForward(a, a->ints.p[a->things.p[i].i]); default: Fail(a, "this corruption %d", a->things.p[i].t); } } static void EvaluateExpr(struct As *a, int i) { if (i == -1) return; if (a->exprs.p[i].isevaluated) return; if (a->exprs.p[i].isvisited) Fail(a, "circular expr"); a->exprs.p[i].isvisited = true; EvaluateExpr(a, a->exprs.p[i].lhs); EvaluateExpr(a, a->exprs.p[i].rhs); a->i = a->exprs.p[i].tok; switch (a->exprs.p[i].kind) { case EX_INT: break; case EX_SYM: a->exprs.p[i].x = ResolveSymbol(a, a->exprs.p[i].x); break; default: break; } a->exprs.p[i].isevaluated = true; } static void Write32(char b[4], int x) { b[0] = x >> 000; b[1] = x >> 010; b[2] = x >> 020; b[3] = x >> 030; } static void MarkUsedSymbols(struct As *a, int i) { if (i == -1) return; MarkUsedSymbols(a, a->exprs.p[i].lhs); MarkUsedSymbols(a, a->exprs.p[i].rhs); if (a->exprs.p[i].kind == EX_SYM) { a->symbols.p[a->exprs.p[i].x].isused = true; } } static void Evaluate(struct As *a) { int i; struct Expr *e; for (i = 0; i < a->relas.n; ++i) { EvaluateExpr(a, a->relas.p[i].expr); if (a->relas.p[i].kind == R_X86_64_PC32) { e = a->exprs.p + a->relas.p[i].expr; if (e->kind == EX_SYM && a->symbols.p[e->x].stb == STB_LOCAL && a->symbols.p[e->x].section == a->relas.p[i].section) { a->relas.p[i].isdead = true; Write32((a->sections.p[a->relas.p[i].section].binary.p + a->relas.p[i].offset), (a->symbols.p[e->x].offset - a->relas.p[i].offset + a->relas.p[i].addend)); } } } for (i = 0; i < a->relas.n; ++i) { if (a->relas.p[i].isdead) continue; MarkUsedSymbols(a, a->relas.p[i].expr); } } static void MarkUndefinedSymbolsGlobal(struct As *a) { int i; for (i = 0; i < a->symbols.n; ++i) { if (a->symbols.p[i].isused && !a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) { a->symbols.p[i].stb = STB_GLOBAL; } } } static bool IsLocal(struct As *a, int name) { if (name < 0) return true; return a->slices.p[name].n >= 2 && !memcmp(a->slices.p[name].p, ".L", 2); } static bool IsLiveSymbol(struct As *a, int i) { return !(!a->symbols.p[i].isused && a->symbols.p[i].stb == STB_LOCAL && a->symbols.p[i].section && IsLocal(a, a->symbols.p[i].name)); } static void Objectify(struct As *a, int path) { char *p; int i, j, s, e; struct ElfWriter *elf; elf = elfwriter_open(a->strings.p[path], 0644, EM_NEXGEN32E); for (i = 0; i < a->symbols.n; ++i) { if (!IsLiveSymbol(a, i)) continue; p = strndup(a->slices.p[a->symbols.p[i].name].p, a->slices.p[a->symbols.p[i].name].n); a->symbols.p[i].ref = elfwriter_appendsym( elf, p, ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type), a->symbols.p[i].stv, a->symbols.p[i].offset, a->symbols.p[i].size); if (a->symbols.p[i].section >= SHN_LORESERVE) { elfwriter_setsection(elf, a->symbols.p[i].ref, a->symbols.p[i].section); } free(p); } for (i = 0; i < a->sections.n; ++i) { elfwriter_align(elf, a->sections.p[i].align, 0); s = elfwriter_startsection(elf, a->strings.p[a->sections.p[i].name], a->sections.p[i].type, a->sections.p[i].flags); for (j = 0; j < a->symbols.n; ++j) { if (!IsLiveSymbol(a, j)) continue; if (a->symbols.p[j].section != i) continue; elfwriter_setsection(elf, a->symbols.p[j].ref, s); } for (j = 0; j < a->relas.n; ++j) { if (a->relas.p[j].isdead) continue; if (a->relas.p[j].section != i) continue; e = a->relas.p[j].expr; a->i = a->exprs.p[e].tok; switch (a->exprs.p[e].kind) { case EX_INT: break; case EX_SYM: elfwriter_appendrela(elf, a->relas.p[j].offset, a->symbols.p[a->exprs.p[e].x].ref, a->relas.p[j].kind, a->relas.p[j].addend); break; case EX_ADD: if (a->exprs.p[a->exprs.p[e].lhs].kind == EX_SYM && a->exprs.p[a->exprs.p[e].rhs].kind == EX_INT) { elfwriter_appendrela( elf, a->relas.p[j].offset, a->symbols.p[a->exprs.p[a->exprs.p[e].lhs].x].ref, a->relas.p[j].kind, a->relas.p[j].addend + a->exprs.p[a->exprs.p[e].rhs].x); } else { Fail(a, "bad addend"); } break; default: Fail(a, "unsupported relocation type"); } } if (a->sections.p[i].binary.n) { memcpy(elfwriter_reserve(elf, a->sections.p[i].binary.n), a->sections.p[i].binary.p, a->sections.p[i].binary.n); } elfwriter_commit(elf, a->sections.p[i].binary.n); elfwriter_finishsection(elf); } elfwriter_close(elf); } static void CheckIntegrity(struct As *a) { int i; for (i = 0; i < a->things.n; ++i) { CHECK_LT((int)a->things.p[i].s, a->sauces.n); switch (a->things.p[i].t) { case TT_INT: case TT_FORWARD: case TT_BACKWARD: CHECK_LT(a->things.p[i].i, a->ints.n); break; case TT_FLOAT: CHECK_LT(a->things.p[i].i, a->floats.n); break; case TT_SLICE: CHECK_LT(a->things.p[i].i, a->slices.n); break; default: break; } } for (i = 0; i < a->sections.n; ++i) { CHECK_LT(a->sections.p[i].name, a->strings.n); } for (i = 0; i < a->symbols.n; ++i) { CHECK_LT(a->symbols.p[i].name, a->slices.n); CHECK_LT(a->symbols.p[i].section, a->sections.n); } for (i = 0; i < a->labels.n; ++i) { CHECK_LT(a->labels.p[i].tok, a->things.n); CHECK_LT(a->labels.p[i].symbol, a->symbols.n); } for (i = 0; i < a->relas.n; ++i) { CHECK_LT(a->relas.p[i].expr, a->exprs.n); CHECK_LT(a->relas.p[i].section, a->sections.n); } for (i = 0; i < a->exprs.n; ++i) { CHECK_LT(a->exprs.p[i].tok, a->things.n); if (a->exprs.p[i].lhs != -1) CHECK_LT(a->exprs.p[i].lhs, a->exprs.n); if (a->exprs.p[i].rhs != -1) CHECK_LT(a->exprs.p[i].rhs, a->exprs.n); switch (a->exprs.p[i].kind) { case EX_SYM: CHECK_LT(a->exprs.p[i].x, a->things.n); CHECK(a->things.p[a->exprs.p[i].x].t == TT_SLICE || a->things.p[a->exprs.p[i].x].t == TT_FORWARD || a->things.p[a->exprs.p[i].x].t == TT_BACKWARD); break; default: break; } } } static void PrintThings(struct As *a) { int i; char pbuf[4], fbuf[32]; for (i = 0; i < a->things.n; ++i) { printf("%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[i].s].path], a->sauces.p[a->things.p[i].s].line); switch (a->things.p[i].t) { case TT_INT: printf("TT_INT %jd\n", a->ints.p[a->things.p[i].i]); break; case TT_FLOAT: g_xfmt_p(fbuf, &a->floats.p[a->things.p[i].i], 19, sizeof(fbuf), 0); printf("TT_FLOAT %s\n", fbuf); break; case TT_SLICE: printf("TT_SLICE %.*s\n", a->slices.p[a->things.p[i].i].n, a->slices.p[a->things.p[i].i].p); break; case TT_PUNCT: printf("TT_PUNCT %s\n", PunctToStr(a->things.p[i].i, pbuf)); break; case TT_BACKWARD: printf("TT_BACKWARD %jd\n", a->ints.p[a->things.p[i].i]); break; case TT_FORWARD: printf("TT_FORWARD %jd\n", a->ints.p[a->things.p[i].i]); break; default: abort(); } } } void Assembler(int argc, char *argv[]) { struct As *a; a = NewAssembler(); ReadFlags(a, argc, argv); SaveString(&a->incpaths, strdup(".")); SaveString(&a->incpaths, xdirname(a->strings.p[a->inpath])); Tokenize(a, a->inpath); /* PrintThings(a); */ Assemble(a); /* CheckIntegrity(a); */ Evaluate(a); MarkUndefinedSymbolsGlobal(a); Objectify(a, a->outpath); /* malloc_stats(); */ FreeAssembler(a); }