/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ │vi: set net 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/log/check.h" #include "libc/log/log.h" #include "libc/mem/mem.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/o.h" #include "third_party/gdtoa/gdtoa.h" #include "tool/build/lib/elfwriter.h" /** * @fileoverview Assembler * * This program turns assembly into relocatable NexGen32e ELF objects. * That process is normally an implementation detail of your compiler, * which can embed this program or launch it as a subprocess. Much GNU * style syntax is supported. Your code that gets embedded in an asm() * statement will ultimately end up here. This implementation, has the * advantage of behaving the same across platforms, in a simple single * file implementation that compiles down to a 100kilo ape executable. * * Your assembler supports the following flags: * * -o FILE output path [default: a.out] * -I DIR append include path [default: .] * -W inhibit .warning * -Z inhibit .error and .err * * Your assembler supports the following directives: * * .zero INT... emits int8 * .word INT... emits int16 * .long INT... emits int32 * .quad INT... emits int64 * .ascii STR... emits string * .asciz STR... emits string and 0 byte * .ident STR emits string to .comment section * .float NUMBER... emits binary32 * .double NUMBER... emits binary64 * .float80 NUMBER... emits x86 float (10 bytes) * .ldbl NUMBER... emits x86 float (16 bytes) * .sleb128 NUMBER... emits LEB-128 signed varint * .uleb128 NUMBER... emits LEB-128 unsigned varint * .align BYTES [FILL [MAXSKIP]] emits fill bytes to boundary * .end halts tokenization * .abort crashes assembler * .err aborts (ignorable w/ -Z) * .error STR aborts (ignorable w/ -Z) * .warning STR whines (ignorable w/ -W) * .text enters text section (default) * .data enters data section * .bss enters bss section * .section NAME [SFLG SHT] enters section * .previous enters previous section * .pushsection NAME [SFLG SHT] pushes section * .popsection pops section * .type SYM TYPE sets type of symbol * .size SYM EXPR sets size of symbol * .internal SYM... marks symbol STV_INTERNAL * .hidden SYM... marks symbol STV_HIDDEN * .protected SYM... marks symbol STV_PROTECTED * .globl SYM... marks symbol STB_GLOBAL * .local SYM... marks symbol STB_LOCAL * .weak SYM... marks symbol STB_WEAK * .include FILE assembles file source * .incbin FILE emits file content * .file FILENO PATH dwarf file define * .loc FILENO LINENO dwarf source line * * TYPE can be one of the following: * * - @notype STT_NOTYPE (default) * - @object STT_OBJECT * - @function STT_FUNC * - @common STT_COMMON * - @tls_object STT_TLS * * SHT can be one of the following: * * - @progbits SHT_PROGBITS * - @note SHT_NOTE * - @nobits SHT_NOBITS * - @preinit_array SHT_PREINIT_ARRAY * - @init_array SHT_INIT_ARRAY * - @fini_array SHT_FINI_ARRAY * * SFLG is a string which may have the following characters: * * - a SHF_ALLOC * - w SHF_WRITE * - x SHF_EXECINSTR * - g SHF_GROUP * - M SHF_MERGE * - S SHF_STRINGS * - T SHF_TLS */ #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) L.p = realloc(L.p, ++L.n * sizeof(*L.p)) #define IS(P, N, S) (N == sizeof(S) - 1 && !strncasecmp(P, S, sizeof(S) - 1)) #define BSR(I) (__builtin_clz(I) ^ 31) #define ROUNDUP(X, K) (((X) + (K)-1) & -(K)) #define MAX(X, Y) ((Y) < (X) ? (X) : (Y)) #define LOAD128BE(S) ((unsigned __int128)LOAD64BE(S) << 64 | LOAD64BE((S) + 8)) #define LOAD64BE(S) \ ((unsigned long)((unsigned char *)(S))[0] << 070 | \ (unsigned long)((unsigned char *)(S))[1] << 060 | \ (unsigned long)((unsigned char *)(S))[2] << 050 | \ (unsigned long)((unsigned char *)(S))[3] << 040 | \ (unsigned long)((unsigned char *)(S))[4] << 030 | \ (unsigned long)((unsigned char *)(S))[5] << 020 | \ (unsigned long)((unsigned char *)(S))[6] << 010 | \ (unsigned long)((unsigned char *)(S))[7] << 000) #define ARRAYLEN(A) \ ((sizeof(A) / sizeof(*(A))) / ((unsigned)!(sizeof(A) % sizeof(*(A))))) 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; long *p; } ints; struct Floats { unsigned long n; long double *p; } floats; struct Slices { unsigned long n; struct Slice { unsigned long n; char *p; } * p; } slices; struct Sauces { unsigned long n; struct Sauce { int path; // strings int line; // 1-indexed } * p; } sauces; struct Things { unsigned long n; struct Thing { enum ThingType { TT_INT, TT_FLOAT, TT_SLICE, TT_PUNCT, TT_FORWARD, TT_BACKWARD, } t : 4; int s : 28; // sauces int i; // identity,ints,floats,slices } * p; } things; struct Sections { unsigned long n; struct Section { int name; // strings int flags; int type; int align; struct Slice binary; } * p; } sections; struct Symbols { unsigned long n; struct Symbol { bool isused; int name; // slices int section; // sections int stb; // STB_* int stv; // STV_* int type; // STT_* long offset; long size; struct ElfWriterSymRef ref; } * p; } symbols; struct HashTable { unsigned i, n; struct HashEntry { int h; int i; } * p; } symbolindex; struct Labels { unsigned long n; struct Label { int id; int tok; // things int symbol; // symbols } * p; } labels; struct Relas { unsigned long n; struct Rela { bool isdead; int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...} int expr; // exprs int section; // sections long offset; long addend; } * p; } relas; struct Exprs { unsigned long n; struct Expr { enum ExprKind { EX_INT, // integer EX_SYM, // slice, forward, backward, then symbol 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; int tok; int lhs; int rhs; long x; bool isvisited; bool isevaluated; } * p; } exprs; struct Strings { unsigned long n; char **p; } strings, incpaths; struct SectionStack { unsigned long n; 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 */; static unsigned Hash(const void *p, unsigned long n) { unsigned h, i; for (h = i = 0; i < n; i++) { h += ((unsigned char *)p)[i]; h *= 0x9e3779b1; } return MAX(1, h); } static bool StartsWith(const char *s, const char *prefix) { for (;;) { if (!*prefix) return true; if (!*s) return false; if (*s++ != *prefix++) return false; } } static bool EndsWith(const char *s, const char *suffix) { size_t n, m; n = strlen(s); m = strlen(suffix); if (m > n) return false; return memcmp(s + n - m, suffix, m) == 0; } static char *Format(const char *fmt, ...) { char *res; va_list va; va_start(va, fmt); vasprintf(&res, fmt, va); va_end(va); return res; } static char *DirName(const char *path) { return dirname(strdup(path)); } static char *JoinPaths(const char *path, const char *other) { if (!*other) { return strdup(path); } else if (!*path) { return strdup(other); } else if (StartsWith(other, "/") || !strcmp(path, ".")) { return strdup(other); } else if (EndsWith(path, "/")) { return Format("%s%s", path, other); } else { return Format("%s/%s", path, other); } } static bool IsPunctMergeable(int c) { switch (c) { case ';': case '$': return false; default: return true; } } static char *PunctToStr(int p, char b[4]) { int c, i, j; memset(b, 0, 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); memset(a->exprs.p + a->exprs.n - 1, 0, 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); memset(a->things.p + a->things.n - 1, 0, sizeof(*a->things.p)); } static void AppendRela(struct As *a) { APPEND(a->relas); memset(a->relas.p + a->relas.n - 1, 0, sizeof(*a->relas.p)); } static void AppendSlice(struct As *a) { APPEND(a->slices); memset(a->slices.p + a->slices.n - 1, 0, 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; 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) { 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 (isxdigit(p[*i])) { c = hextoint(p[(*i)++]); if (isxdigit(p[*i])) { c = c * 16 + hextoint(p[(*i)++]); } } 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 CanonicalizeNewline(char *p) { int i = 0, j = 0; while (p[i]) { if (p[i] == '\r' && p[i + 1] == '\n') { i += 2; p[j++] = '\n'; } else if (p[i] == '\r') { i++; p[j++] = '\n'; } else { p[j++] = p[i++]; } } p[j] = '\0'; } static void RemoveBackslashNewline(char *p) { int i, j, n; for (i = j = n = 0; p[i];) { if (p[i] == '\\' && p[i + 1] == '\n') { i += 2; n++; } else if (p[i] == '\n') { p[j++] = p[i++]; for (; n > 0; n--) p[j++] = '\n'; } else { p[j++] = p[i++]; } } for (; n > 0; n--) p[j++] = '\n'; p[j] = '\0'; } static char *ReadFile(const char *path) { char *p; FILE *fp; int buflen, nread, end, n; if (!strcmp(path, "-")) { fp = stdin; } else { fp = fopen(path, "r"); if (!fp) return NULL; } buflen = 4096; nread = 0; p = calloc(1, buflen); for (;;) { end = buflen - 2; n = fread(p + nread, 1, end - nread, fp); if (n == 0) break; nread += n; if (nread == end) { buflen *= 2; p = realloc(p, buflen); } } if (fp != stdin) fclose(fp); if (nread > 0 && p[nread - 1] == '\\') { p[nread - 1] = '\n'; } else if (nread == 0 || p[nread - 1] != '\n') { p[nread++] = '\n'; } p[nread] = '\0'; return p; } 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 = JoinPaths(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; p = SaveString(&a->strings, ReadFile(a->strings.p[path])); if (!memcmp(p, "\357\273\277", 3)) p += 3; CanonicalizeNewline(p); RemoveBackslashNewline(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' || c == ',') { ++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] = strtol(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 == '"') { buf.n = 0; buf.p = NULL; 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, n2; h = Hash(a->slices.p[name].p, a->slices.p[name].n); n = a->symbolindex.n; i = 0; if (n) { k = 0; do { 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)) { return a->symbolindex.p[i].i; } ++k; } while (a->symbolindex.p[i].h); } 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 = Format(".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 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 int NewPrimary(struct As *a, enum ExprKind k, long 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) { int e; 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 long 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, unsigned long n) { struct Slice *s; s = &a->sections.p[a->section].binary; s->p = realloc(s->p, s->n + n); memcpy(s->p + s->n, p, n); s->n += n; } static void EmitByte(struct As *a, unsigned long x) { unsigned char b[1]; b[0] = x >> 000; EmitData(a, b, 1); } static void EmitWord(struct As *a, unsigned long x) { unsigned char b[2]; b[0] = x >> 000; b[1] = x >> 010; EmitData(a, b, 2); } static void EmitLong(struct As *a, unsigned long x) { unsigned char b[4]; b[0] = x >> 000; b[1] = x >> 010; b[2] = x >> 020; b[3] = x >> 030; EmitData(a, b, 4); } void EmitQuad(struct As *a, unsigned long x) { unsigned char b[8]; b[0] = x >> 000; b[1] = x >> 010; b[2] = x >> 020; b[3] = x >> 030; b[4] = x >> 040; b[5] = x >> 050; b[6] = x >> 060; b[7] = x >> 070; EmitData(a, b, 8); } 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; long x; while (!IsPunct(a, a->i, ';')) { 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); } } } static void OnUleb128(struct As *a, struct Slice s) { int c; unsigned long x; while (!IsPunct(a, a->i, ';')) { x = GetInt(a); do { c = x & 0x7f; x >>= 7; if (x) c |= 0x80; EmitByte(a, c); } while (x); } } static void OnZero(struct As *a, struct Slice s) { long n; char *p; while (IsInt(a, a->i)) { n = GetInt(a); p = calloc(n, 1); EmitData(a, p, n); free(p); } } static void OnSpace(struct As *a, struct Slice s) { long n; char *p; p = malloc((n = GetInt(a))); memset(p, IsInt(a, a->i) ? GetInt(a) : 0, 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 *, unsigned long)) { 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 OnByte(struct As *a, struct Slice s) { do { EmitExpr(a, Parse(a), R_X86_64_8, EmitByte); } while (!IsPunct(a, a->i, ';')); } static void OnWord(struct As *a, struct Slice s) { do { EmitExpr(a, Parse(a), R_X86_64_16, EmitWord); } while (!IsPunct(a, a->i, ';')); } static void OnLong(struct As *a, struct Slice s) { do { EmitExpr(a, Parse(a), R_X86_64_32, EmitLong); } while (!IsPunct(a, a->i, ';')); } static void OnQuad(struct As *a, struct Slice s) { do { EmitExpr(a, Parse(a), R_X86_64_64, EmitQuad); } while (!IsPunct(a, a->i, ';')); } static void OnFloat(struct As *a, struct Slice s) { float f; char b[4]; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else if (IsInt(a, a->i)) { f = GetInt(a); } else { break; } memcpy(b, &f, 4); EmitData(a, b, 4); } } static void OnDouble(struct As *a, struct Slice s) { double f; char b[8]; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else if (IsInt(a, a->i)) { f = GetInt(a); } else { break; } memcpy(b, &f, 8); EmitData(a, b, 8); } } static void OnLongDouble(struct As *a, int n) { char b[16]; long double f; for (;;) { if (IsFloat(a, a->i)) { f = GetFloat(a); } else if (IsInt(a, a->i)) { f = GetInt(a); } else { break; } memset(b, 0, 16); memcpy(b, &f, sizeof(f)); EmitData(a, b, n); } } 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; while (IsSlice(a, a->i)) { arg = GetSlice(a); EmitData(a, arg.p, arg.n); } } static void OnAsciz(struct As *a, struct Slice s) { struct Slice arg; while (IsSlice(a, a->i)) { arg = GetSlice(a); EmitData(a, arg.p, arg.n); EmitByte(a, 0); } } 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 (__builtin_popcountl(align) != 1) Fail(a, "alignment not power of 2"); fill = (a->sections.p[a->section].flags & SHF_EXECINSTR) ? 0x90 : 0; maxskip = 268435456; if (IsInt(a, a->i)) { fill = GetInt(a); if (IsInt(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 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; 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 (IsSlice(a, a->i)) { flags = SectionFlags(a, GetSlice(a)); if (IsSlice(a, a->i)) { type = SectionType(a, GetSlice(a)); } } SetSection(a, GrabSection(a, name, flags, type)); } 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); 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); 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); a->symbols.p[i].size = GetInt(a); } static void OpVisibility(struct As *a, int visibility) { int i; while (IsSlice(a, a->i)) { i = GetSymbol(a, a->things.p[a->i++].i); a->symbols.p[i].stv = visibility; } } 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; while (IsSlice(a, a->i)) { i = GetSymbol(a, a->things.p[a->i++].i); a->symbols.p[i].stb = bind; } } 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 LOAD64BE(k); } static unsigned __int128 MakeKey128(const char *p, int n) { char k[16] = {0}; CopyLower(k, p, n); return LOAD128BE(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) >> 1; y = LOAD64BE(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) >> 1; y = LOAD64BE(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; struct Slice wut; if ((reg = FindRegReg(GetSlice(a))) == -1) InvalidRegister(a); return reg; } static int GetRegisterRm(struct As *a) { int reg; struct Slice wut; 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, scale, 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 ((str = GetSlice(a)).n) { 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 (!IsPunct(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 (!IsPunct(a, a->i, ')')) { modrm |= (BSR(GetInt(a)) & 3) << 6; } } else { modrm |= 4 << 3; // puttin' on the riz } 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) { reg &= 7; reg <<= 3; if (modrm & ISREG) { EmitByte(a, 0300 | reg | modrm & 7); } else { if (modrm & ISRIP) { EmitByte(a, 005 | reg); } else if (modrm & (HASBASE | HASINDEX)) { EmitByte(a, 0204 | reg); // suboptimal EmitByte(a, modrm); } else { EmitByte(a, 004 | reg); EmitByte(a, 045); } EmitExpr( a, disp, a->pcrelative && ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) ? a->pcrelative : R_X86_64_32S, EmitLong); } } 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: EmitByte(a, OSZ); 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) { EmitRex(a, reg | modrm); EmitOpModrm(a, op, reg, modrm, disp, skew); } static void OnLea(struct As *a, struct Slice s) { int modrm, reg, disp; modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x8D, reg, modrm, disp, 0); } static void OnMov(struct As *a, struct Slice s) { int reg, modrm, disp, imm; if (IsPunct(a, a->i, '$')) { ++a->i; imm = Parse(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: EmitRex(a, reg); EmitByte(a, OSZ); 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); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x88, reg, modrm, disp, 1); } else { // modrm -> reg modrm = ParseModrm(a, &disp); 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); 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); reg = GetRegisterReg(a); EmitByte(a, REXW); EmitByte(a, 0x63); EmitModrm(a, reg, modrm, disp); } static noinline 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); 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); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, op << 3, reg, modrm, disp, 1); } else { // modrm -> reg modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); EmitRexOpModrm(a, op << 3 | 2, reg, modrm, disp, 1); } } static noinline void OpAlu(struct As *a, struct Slice opname, int op) { OpAluImpl(a, opname, op); } static noinline 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); } 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; modrm = ParseModrm(a, &disp); reg = GetOpSize(a, opname, modrm, 1) << 3 | op; EmitRexOpModrm(a, 0xC0, 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 EmitByte(a, imm); } static noinline void OpBsu(struct As *a, struct Slice opname, int op) { OpBsuImpl(a, opname, op); } static int OpF6(struct As *a, struct Slice s, int reg) { int modrm, imm, disp; modrm = ParseModrm(a, &disp); reg |= GetOpSize(a, s, modrm, 1) << 3; EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1); return 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); reg = OpF6(a, s, 0); // suboptimal EmitImm(a, reg, imm); } else { reg = GetRegisterReg(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x84, 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); modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x69, reg, modrm, disp, 0); EmitImm(a, reg, imm); } else { modrm = ParseModrm(a, &disp); if (IsPunct(a, a->i, ';')) { reg = GetOpSize(a, s, modrm, 1) << 3 | 5; EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1); } else { reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x0FAF, reg, modrm, disp, 0); } } } static void OpBit(struct As *a, int op) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); 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); 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))) { skew = 1; ++a->i; reg = GetRegisterReg(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0); } else { skew = 0; ConsumePunct(a, '$'); imm = GetInt(a); reg = GetRegisterReg(a); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0); EmitByte(a, imm); } } 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); modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, opWsdVsd, reg, modrm, disp, 0); } else { modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); EmitRexOpModrm(a, opVsdWsd, 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 OnMovdq(struct As *a, struct Slice s) { int reg, modrm, boop, disp; EmitByte(a, 0x66); // todo mmx if (IsRegister(a, a->i)) { reg = GetRegisterReg(a); modrm = ParseModrm(a, &disp); boop = ((reg & 070) >> 3) == 4 ? 0x10 : 0; } else { modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); boop = ((reg & 070) >> 3) == 4 ? 0x10 : 0; } 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 noinline 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); reg = GetRegisterReg(a); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static noinline void OpSse(struct As *a, int op) { OpSseImpl(a, op); } static noinline void OpSseIbImpl(struct As *a, int op) { int imm; ConsumePunct(a, '$'); imm = Parse(a); OpSse(a, op); EmitExpr(a, imm, R_X86_64_8, EmitByte); } static noinline 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 OnMovq(struct As *a, struct Slice s) { if (HasXmmOnLine(a)) { OnMovdq(a, s); } 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 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 (IsPunct(a, a->i, ';')) { 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 noinline void OpCmovccImpl(struct As *a, int cc) { int reg, modrm, disp; modrm = ParseModrm(a, &disp); reg = GetRegisterReg(a); EmitRexOpModrm(a, 0x0F40 | cc, reg, modrm, disp, 0); } static noinline void OpCmovcc(struct As *a, int cc) { OpCmovccImpl(a, cc); } static noinline void OpSetccImpl(struct As *a, int cc) { int modrm, disp; modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, 0x0F90 | cc, 6, modrm, disp, 0); } static noinline 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); // TODO: DWARF } static void OnLoc(struct As *a, struct Slice s) { int fileno, lineno; fileno = GetInt(a); lineno = GetInt(a); // 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 noinline 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 & ISRIP) || !(modrm & (HASBASE | HASINDEX))) { modrm |= ISRIP; a->pcrelative = R_X86_64_GOTPCRELX; } EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0); a->pcrelative = 0; } else { EmitByte(a, 0x0F); EmitByte(a, 0x80 + cc); EmitExpr(a, disp, R_X86_64_PC32, EmitLong); } } static noinline void OpJmp(struct As *a, int cc) { OpJmpImpl(a, cc); } static noinline void OpFpu1Impl(struct As *a, int op, int reg) { int modrm, disp; modrm = ParseModrm(a, &disp); EmitRexOpModrm(a, op, reg, modrm, disp, 0); } static noinline void OpFpu1(struct As *a, int op, int reg) { OpFpu1Impl(a, op, reg); } static void OnFucomi(struct As *a, struct Slice s) { int reg, rm; rm = !IsPunct(a, a->i, ';') ? GetRegisterRm(a) : 1; reg = !IsPunct(a, a->i, ';') ? GetRegisterReg(a) : 0; if (reg & 7) Fail(a, "bad register"); EmitByte(a, 0xDB); EmitByte(a, 0350 | rm & 7); } static void OnFxch(struct As *a, struct Slice s) { int rm; rm = !IsPunct(a, a->i, ';') ? 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); } // 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 OnFcomip(struct As *a, struct Slice s) { EmitVarword(a, 0xdff1); } 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 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, 0); } 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 OnFucomip(struct As *a, struct Slice s) { EmitVarword(a, 0xDFE9); } 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 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 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 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 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 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 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 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}, // {".data", OnData}, // {".double", OnDouble}, // {".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}, // {".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}, // {"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}, // {"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}, // {"fcomip", OnFcomip}, // {"fdivrp", OnFdivrp}, // {"fildl", OnFildl}, // {"fildll", OnFildll}, // {"fildq", OnFildq}, // {"filds", OnFilds}, // {"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}, // {"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}, // {"lea", OnLea}, // {"leave", OnLeave}, // {"lodsb", OnLodsb}, // {"lodsl", OnLodsl}, // {"lodsq", OnLodsq}, // {"lodsw", OnLodsw}, // {"maxpd", OnMaxpd}, // {"maxps", OnMaxps}, // {"maxsd", OnMaxsd}, // {"maxss", OnMaxss}, // {"minpd", OnMinpd}, // {"minps", OnMinps}, // {"minsd", OnMinsd}, // {"minss", OnMinss}, // {"mov", OnMov}, // {"movabs", OnMov}, // {"movapd", OnMovapd}, // {"movaps", OnMovaps}, // {"movb", OnMov}, // {"movd", OnMovdq}, // {"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}, // {"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}, // {"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}, // {"test", OnTest}, // {"testb", OnTest}, // {"testl", OnTest}, // {"testq", OnTest}, // {"testw", OnTest}, // {"ucomisd", OnUcomisd}, // {"ucomiss", OnUcomiss}, // {"ud2", OnUd2}, // {"unpckhpd", OnUnpckhpd}, // {"unpcklpd", OnUnpcklpd}, // {"wait", OnFwait}, // {"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}, // {"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) >> 1; y = LOAD64BE(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) >> 1; y = LOAD128BE(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 (IsPunct(a, a->i, ';')) { 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 (IsPunct(a, a->i, ';')) { ++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: DebugBreak(); Fail(a, "this corruption"); } } 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 MarkUndefinedSymbolsGlobal(struct As *a) { int i; for (i = 0; i < a->symbols.n; ++i) { if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) { a->symbols.p[i].stb = STB_GLOBAL; } } } 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 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) { int i, j, s; struct ElfWriter *elf; elf = elfwriter_open(a->strings.p[path], 0644); for (i = 0; i < a->symbols.n; ++i) { if (!IsLiveSymbol(a, i)) continue; a->symbols.p[i].ref = elfwriter_appendsym( elf, strndup(a->slices.p[a->symbols.p[i].name].p, a->slices.p[a->symbols.p[i].name].n), 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); } 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; a->i = a->exprs.p[a->relas.p[j].expr].tok; switch (a->exprs.p[a->relas.p[j].expr].kind) { case EX_INT: break; case EX_SYM: elfwriter_appendrela( elf, a->relas.p[j].offset, a->symbols.p[a->exprs.p[a->relas.p[j].expr].x].ref, a->relas.p[j].kind, a->relas.p[j].addend); break; case EX_ADD: if (a->exprs.p[a->exprs.p[j].lhs].kind == EX_SYM && a->exprs.p[a->exprs.p[j].rhs].kind == EX_INT) { elfwriter_appendrela( elf, a->relas.p[j].offset, a->symbols.p[a->exprs.p[a->exprs.p[j].lhs].x].ref, a->relas.p[j].kind, a->relas.p[j].addend + a->exprs.p[a->exprs.p[j].rhs].x); } else { Fail(a, "bad addend"); } break; default: Fail(a, "unsupported relocation type"); } } 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 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 %ld\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 %d\n", a->ints.p[a->things.p[i].i]); break; case TT_FORWARD: printf("TT_FORWARD %d\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, DirName(a->strings.p[a->inpath])); Tokenize(a, a->inpath); /* PrintThings(a); */ Assemble(a); Evaluate(a); MarkUndefinedSymbolsGlobal(a); Objectify(a, a->outpath); malloc_stats(); FreeAssembler(a); } int main(int argc, char *argv[]) { showcrashreports(); if (argc == 1) { system("o//third_party/chibicc/as.com -o /tmp/o third_party/chibicc/hog.s"); system("objdump -xwd /tmp/o"); exit(0); } Assembler(argc, argv); return 0; }