cosmopolitan/third_party/chibicc/as.c

3922 lines
132 KiB
C
Raw Normal View History

2020-12-19 19:21:04 +00:00
/*-*- 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"
2020-12-24 07:42:56 +00:00
#include "libc/log/check.h"
2020-12-19 19:21:04 +00:00
#include "libc/log/log.h"
2020-12-28 19:38:38 +00:00
#include "libc/macros.h"
2020-12-19 19:21:04 +00:00
#include "libc/mem/mem.h"
2020-12-28 19:38:38 +00:00
#include "libc/nexgen32e/bsr.h"
2020-12-19 19:21:04 +00:00
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
2020-12-28 01:05:03 +00:00
#include "libc/x/x.h"
#include "third_party/chibicc/file.h"
2020-12-19 19:21:04 +00:00
#include "third_party/gdtoa/gdtoa.h"
#include "tool/build/lib/elfwriter.h"
2020-12-24 07:42:56 +00:00
/**
* @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
2020-12-19 19:21:04 +00:00
#define HASASZ 0x00010000
#define HASBASE 0x00020000
#define HASINDEX 0x00040000
#define ISRIP 0x00080000
#define ISREG 0x00100000
2020-12-28 19:38:38 +00:00
#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 MAX(X, Y) ((Y) < (X) ? (X) : (Y))
#define LOAD128BE(S) ((unsigned __int128)LOAD64BE(S) << 64 | LOAD64BE((S) + 8))
2020-12-24 07:42:56 +00:00
#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)
struct As {
int i; // things
int section; // sections
int previous; // sections
int inpath; // strings
int outpath; // strings
int counter;
2020-12-25 00:01:48 +00:00
int pcrelative;
2020-12-24 07:42:56 +00:00
bool inhibiterr;
bool inhibitwarn;
2020-12-19 19:21:04 +00:00
struct Ints {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
long *p;
} ints;
struct Floats {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
long double *p;
} floats;
struct Slices {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Slice {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
char *p;
} * p;
} slices;
struct Sauces {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Sauce {
2020-12-26 10:09:07 +00:00
unsigned path; // strings
unsigned line; // 1-indexed
2020-12-19 19:21:04 +00:00
} * p;
} sauces;
struct Things {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Thing {
enum ThingType {
TT_INT,
TT_FLOAT,
TT_SLICE,
TT_PUNCT,
TT_FORWARD,
TT_BACKWARD,
2020-12-24 07:42:56 +00:00
} t : 4;
2020-12-26 10:09:07 +00:00
unsigned s : 28; // sauces
unsigned i; // identity,ints,floats,slices
2020-12-19 19:21:04 +00:00
} * p;
} things;
struct Sections {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Section {
2020-12-26 10:09:07 +00:00
unsigned name; // strings
2020-12-19 19:21:04 +00:00
int flags;
int type;
int align;
struct Slice binary;
} * p;
} sections;
struct Symbols {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Symbol {
2020-12-24 07:42:56 +00:00
bool isused;
2020-12-26 10:09:07 +00:00
unsigned char stb; // STB_*
unsigned char stv; // STV_*
unsigned char type; // STT_*
unsigned name; // slices
unsigned section; // sections
2020-12-24 07:42:56 +00:00
long offset;
2020-12-19 19:21:04 +00:00
long size;
2020-12-24 07:42:56 +00:00
struct ElfWriterSymRef ref;
2020-12-19 19:21:04 +00:00
} * p;
} symbols;
2020-12-24 07:42:56 +00:00
struct HashTable {
unsigned i, n;
struct HashEntry {
2020-12-26 10:09:07 +00:00
unsigned h;
unsigned i;
2020-12-24 07:42:56 +00:00
} * p;
} symbolindex;
2020-12-19 19:21:04 +00:00
struct Labels {
2020-12-24 07:42:56 +00:00
unsigned long n;
2020-12-19 19:21:04 +00:00
struct Label {
2020-12-26 10:09:07 +00:00
unsigned id;
unsigned tok; // things
unsigned symbol; // symbols
2020-12-19 19:21:04 +00:00
} * p;
} labels;
2020-12-24 07:42:56 +00:00
struct Relas {
unsigned long n;
struct Rela {
bool isdead;
2020-12-26 10:09:07 +00:00
int kind; // R_X86_64_{16,32,64,PC8,PC32,PLT32,GOTPCRELX,...}
unsigned expr; // exprs
unsigned section; // sections
2020-12-24 07:42:56 +00:00
long offset;
long addend;
} * p;
} relas;
struct Exprs {
unsigned long n;
struct Expr {
enum ExprKind {
EX_INT, // integer
2020-12-26 10:09:07 +00:00
EX_SYM, // things (then symbols after eval)
2020-12-24 07:42:56 +00:00
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;
2020-12-26 10:09:07 +00:00
unsigned tok;
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
};
static const char kPrefixByte[30] = {
2020-12-24 07:42:56 +00:00
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,
2020-12-19 19:21:04 +00:00
};
static const char kPrefix[30][8] = {
2020-12-24 07:42:56 +00:00
"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",
2020-12-19 19:21:04 +00:00
};
2020-12-24 07:42:56 +00:00
static const char kSegmentByte[6] = {0x2E, 0x3E, 0x26, 0x64, 0x65, 0x36};
static const char kSegment[6][2] = {"cs", "ds", "es", "fs", "gs", "ss"};
2020-12-19 19:21:04 +00:00
/**
* Context-sensitive register encoding information.
*
* rex
* logsize
* 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 },
2020-12-24 07:42:56 +00:00
{"eiz", -1, -1, -1, 4 | 2<<3 },
2020-12-19 19:21:04 +00:00
{"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 },
2020-12-24 07:42:56 +00:00
{"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 },
2020-12-19 19:21:04 +00:00
{"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 },
2020-12-24 07:42:56 +00:00
{"riz", -1, -1, -1, 4 | 3<<3 },
2020-12-19 19:21:04 +00:00
{"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 },
2020-12-24 07:42:56 +00:00
{"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 },
2020-12-19 19:21:04 +00:00
{"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 */;
2020-12-24 07:42:56 +00:00
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 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;
}
2020-12-19 19:21:04 +00:00
2020-12-19 21:39:09 +00:00
static void PrintSlice(struct Slice s) {
fprintf(stderr, "%.*s\n", s.n, s.p);
}
2020-12-24 07:42:56 +00:00
static char *SaveString(struct Strings *l, char *p) {
APPEND((*l));
2020-12-19 19:21:04 +00:00
l->p[l->n - 1] = p;
2020-12-24 07:42:56 +00:00
return p;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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));
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static int AppendSection(struct As *a, int name, int flags, int type) {
2020-12-19 19:21:04 +00:00
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;
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
a->section = 1;
return a;
}
2020-12-24 07:42:56 +00:00
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]);
2020-12-28 01:05:03 +00:00
} else if (startswith(argv[i], "-o")) {
2020-12-24 07:42:56 +00:00
a->outpath = StrDup(a, argv[i] + 2);
} else if (!strcmp(argv[i], "-I")) {
SaveString(&a->incpaths, strdup(argv[++i]));
2020-12-28 01:05:03 +00:00
} else if (startswith(argv[i], "-I")) {
2020-12-24 07:42:56 +00:00
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]);
}
2020-12-19 19:21:04 +00:00
}
}
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;
2020-12-24 07:42:56 +00:00
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
2020-12-19 19:21:04 +00:00
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;
}
}
2020-12-24 07:42:56 +00:00
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) {
2020-12-28 01:05:03 +00:00
path = xjoinpaths(a->incpaths.p[i], file);
2020-12-24 07:42:56 +00:00
if (stat(path, &st) != -1 && S_ISREG(st.st_mode)) return path;
free(path);
}
return NULL;
}
static void Tokenize(struct As *a, int path) {
2020-12-19 19:21:04 +00:00
int c, i, line;
char *p, *path2;
struct Slice buf;
2020-12-24 07:42:56 +00:00
bool bol, isfloat, isfpu;
2020-12-28 01:05:03 +00:00
p = SaveString(&a->strings, read_file(a->strings.p[path]));
p = skip_bom(p);
canonicalize_newline(p);
remove_backslash_newline(p);
2020-12-19 19:21:04 +00:00
line = 1;
bol = true;
while ((c = *p)) {
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 21:39:09 +00:00
if (c == '#' || (c == '/' && bol) || (c == '/' && p[1] == '/')) {
p = strchr(p, '\n');
2020-12-19 19:21:04 +00:00
continue;
}
if (c == '\n') {
2020-12-24 07:42:56 +00:00
AppendThing(a);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].t = TT_PUNCT;
2020-12-24 07:42:56 +00:00
a->things.p[a->things.n - 1].s = AppendSauce(a, path, line);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].i = ';';
++p;
2020-12-19 19:21:04 +00:00
bol = true;
++line;
2020-12-19 21:39:09 +00:00
continue;
}
bol = false;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
c == '\v' || c == ',') {
++p;
continue;
}
2020-12-24 07:42:56 +00:00
if ((c & 0x80) || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
c == '_' || c == '%' || c == '@' ||
(c == '.' && !('0' <= p[1] && p[1] <= '9'))) {
isfpu = false;
2020-12-19 21:39:09 +00:00
for (i = 1;; ++i) {
2020-12-24 07:42:56 +00:00
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] == ')')))) {
2020-12-19 21:39:09 +00:00
break;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
if (i == 2 && p[i - 2] == '%' && p[i - 1] == 's' && p[i] == 't') {
isfpu = true;
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
if (i == 4 && !strncasecmp(p, ".end", 4)) break;
AppendThing(a);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].t = TT_SLICE;
2020-12-24 07:42:56 +00:00
a->things.p[a->things.n - 1].s = AppendSauce(a, path, line);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].i = a->slices.n;
2020-12-24 07:42:56 +00:00
AppendSlice(a);
2020-12-19 21:39:09 +00:00
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')) {
2020-12-24 07:42:56 +00:00
isfloat = c == '.';
2020-12-19 21:39:09 +00:00
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;
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
} else if ((p[1] == 'b' || p[1] == 'B') &&
('0' <= p[2] && p[2] <= '9')) {
2020-12-19 21:39:09 +00:00
for (i = 2;; ++i) {
if (!(p[i] == '0' || p[i] == '1')) break;
}
2020-12-19 19:21:04 +00:00
} else {
for (i = 1;; ++i) {
2020-12-19 21:39:09 +00:00
if (!('0' <= p[i] && p[i] <= '7')) break;
2020-12-19 19:21:04 +00:00
}
}
2020-12-19 21:39:09 +00:00
} 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;
2020-12-19 19:21:04 +00:00
}
2020-12-19 21:39:09 +00:00
break;
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
AppendThing(a);
2020-12-19 21:39:09 +00:00
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 {
2020-12-19 19:21:04 +00:00
APPEND(a->ints);
2020-12-19 21:39:09 +00:00
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;
2020-12-24 07:42:56 +00:00
++i;
2020-12-19 21:39:09 +00:00
} else if (p[i] == 'b' || p[i] == 'B') {
a->things.p[a->things.n - 1].t = TT_BACKWARD;
2020-12-24 07:42:56 +00:00
++i;
2020-12-19 21:39:09 +00:00
} else {
a->things.p[a->things.n - 1].t = TT_INT;
2020-12-19 19:21:04 +00:00
}
2020-12-19 21:39:09 +00:00
}
2020-12-24 07:42:56 +00:00
a->things.p[a->things.n - 1].s = AppendSauce(a, path, line);
2020-12-19 21:39:09 +00:00
p += i;
continue;
}
if (c == '\'') {
i = 1;
c = p[i++];
c = ReadCharLiteral(&buf, c, p, &i);
if (p[i] == '\'') ++i;
p += i;
2020-12-24 07:42:56 +00:00
AppendThing(a);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].t = TT_INT;
2020-12-24 07:42:56 +00:00
a->things.p[a->things.n - 1].s = AppendSauce(a, path, line);
2020-12-19 21:39:09 +00:00
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;
2020-12-24 07:42:56 +00:00
if ((path2 = FindInclude(a, buf.p))) {
Tokenize(a, StrDup(a, path2));
free(path2);
free(buf.p);
2020-12-19 21:39:09 +00:00
} else {
2020-12-24 07:42:56 +00:00
Fail(a, "not found: %s", buf.p);
2020-12-19 19:21:04 +00:00
}
2020-12-19 21:39:09 +00:00
} else {
2020-12-24 07:42:56 +00:00
SaveString(&a->strings, buf.p);
AppendThing(a);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].t = TT_SLICE;
2020-12-24 07:42:56 +00:00
a->things.p[a->things.n - 1].s = AppendSauce(a, path, line);
2020-12-19 21:39:09 +00:00
a->things.p[a->things.n - 1].i = a->slices.n;
2020-12-24 07:42:56 +00:00
AppendSlice(a);
2020-12-19 21:39:09 +00:00
a->slices.p[a->slices.n - 1] = buf;
2020-12-19 19:21:04 +00:00
}
2020-12-19 21:39:09 +00:00
continue;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
++p;
}
}
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
APPEND(a->symbols);
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnSymbol(struct As *a, int name) {
2020-12-19 19:21:04 +00:00
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;
2020-12-24 07:42:56 +00:00
a->symbols.p[i].offset = a->sections.p[a->section].binary.n;
2020-12-19 19:21:04 +00:00
a->i += 2;
}
2020-12-24 07:42:56 +00:00
static void OnLocalLabel(struct As *a, int id) {
int i;
char *name;
2020-12-28 01:05:03 +00:00
name = xasprintf(".Label.%d", a->counter++);
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
APPEND(a->labels);
a->labels.p[a->labels.n - 1].id = id;
2020-12-24 07:42:56 +00:00
a->labels.p[a->labels.n - 1].tok = a->i;
a->labels.p[a->labels.n - 1].symbol = i;
2020-12-19 19:21:04 +00:00
a->i += 2;
}
2020-12-24 07:42:56 +00:00
static void SetSection(struct As *a, int section) {
2020-12-19 19:21:04 +00:00
a->previous = a->section;
a->section = section;
}
2020-12-24 07:42:56 +00:00
static bool IsInt(struct As *a, int i) {
2020-12-19 19:21:04 +00:00
return a->things.p[i].t == TT_INT;
}
2020-12-24 07:42:56 +00:00
static bool IsFloat(struct As *a, int i) {
2020-12-19 19:21:04 +00:00
return a->things.p[i].t == TT_FLOAT;
}
2020-12-24 07:42:56 +00:00
static bool IsSlice(struct As *a, int i) {
2020-12-19 19:21:04 +00:00
return a->things.p[i].t == TT_SLICE;
}
2020-12-24 07:42:56 +00:00
static bool IsPunct(struct As *a, int i, int c) {
2020-12-19 19:21:04 +00:00
return a->things.p[i].t == TT_PUNCT && a->things.p[i].i == c;
}
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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 == '%');
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void ConsumePunct(struct As *a, int c) {
char pb[4];
if (IsPunct(a, a->i, c)) {
2020-12-19 19:21:04 +00:00
++a->i;
} else {
2020-12-24 07:42:56 +00:00
Fail(a, "expected %s", PunctToStr(c, pb));
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
Fail(a, "expected int or label");
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
*rest = i;
return x;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
// unary = ("+" | "-" | "!" | "~") unary
// | postfix
static int ParseUnary(struct As *a, int *rest, int i) {
2020-12-19 19:21:04 +00:00
int x;
2020-12-24 07:42:56 +00:00
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);
}
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
x = ParsePostfix(a, rest, i);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
return x;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
a->exprs.p[x].x %= a->exprs.p[y].x;
} else {
x = NewBinary(a, EX_REM, x, y);
}
} else {
*rest = i;
return x;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
a->exprs.p[x].x >>= a->exprs.p[y].x & 63;
} else {
x = NewBinary(a, EX_SHR, x, y);
}
} else {
*rest = i;
return x;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-25 00:01:48 +00:00
a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x;
2020-12-24 07:42:56 +00:00
} else {
x = NewBinary(a, EX_EQ, x, y);
}
} else if (IsPunct(a, i, '!' << 8 | '=')) {
y = ParseRelational(a, &i, i + 1);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-25 00:01:48 +00:00
a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x;
2020-12-24 07:42:56 +00:00
} else {
x = NewBinary(a, EX_NE, x, y);
}
} else {
*rest = i;
return x;
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
// 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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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);
2020-12-26 10:09:07 +00:00
if (a->exprs.p[x].kind == EX_INT && a->exprs.p[y].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
memcpy(b, &f, 8);
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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) {
2020-12-19 19:21:04 +00:00
struct Slice arg;
while (IsSlice(a, a->i)) {
2020-12-24 07:42:56 +00:00
arg = GetSlice(a);
EmitData(a, arg.p, arg.n);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
static void OnAsciz(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
struct Slice arg;
while (IsSlice(a, a->i)) {
2020-12-24 07:42:56 +00:00
arg = GetSlice(a);
EmitData(a, arg.p, arg.n);
EmitByte(a, 0);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
static void OnAbort(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
Fail(a, "aborted");
}
2020-12-24 07:42:56 +00:00
static void OnErr(struct As *a, struct Slice s) {
if (a->inhibiterr) return;
2020-12-19 19:21:04 +00:00
Fail(a, "error");
}
2020-12-24 07:42:56 +00:00
static void OnError(struct As *a, struct Slice s) {
struct Slice msg = GetSlice(a);
if (a->inhibiterr) return;
2020-12-19 19:21:04 +00:00
Fail(a, "%.*s", msg.n, msg.p);
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnText(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
SetSection(a, 1);
}
2020-12-24 07:42:56 +00:00
static void OnData(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
SetSection(a, 2);
}
2020-12-24 07:42:56 +00:00
static void OnBss(struct As *a, struct Slice s) {
SetSection(a, 3);
}
static void OnPrevious(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
SetSection(a, a->previous);
}
2020-12-24 07:42:56 +00:00
static void OnAlign(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
long i, n, align, fill, maxskip;
align = GetInt(a);
2020-12-24 07:42:56 +00:00
if (__builtin_popcountl(align) != 1) Fail(a, "alignment not power of 2");
2020-12-19 19:21:04 +00:00
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);
2020-12-24 07:42:56 +00:00
for (i = 0; i < n; ++i) EmitByte(a, fill);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static int SectionFlag(struct As *a, int c) {
2020-12-19 19:21:04 +00:00
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);
}
}
2020-12-24 07:42:56 +00:00
static int SectionFlags(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
int i, flags;
for (flags = i = 0; i < s.n; ++i) {
flags |= SectionFlag(a, s.p[i]);
}
return flags;
}
2020-12-24 07:42:56 +00:00
static int SectionType(struct As *a, struct Slice s) {
if (IS(s.p, s.n, "@progbits") || IS(s.p, s.n, "SHT_PROGBITS")) {
2020-12-19 19:21:04 +00:00
return SHT_PROGBITS;
2020-12-24 07:42:56 +00:00
} else if (IS(s.p, s.n, "@note") || IS(s.p, s.n, "SHT_NOTE")) {
2020-12-19 19:21:04 +00:00
return SHT_NOTE;
2020-12-24 07:42:56 +00:00
} else if (IS(s.p, s.n, "@nobits") || IS(s.p, s.n, "SHT_NOBITS")) {
2020-12-19 19:21:04 +00:00
return SHT_NOBITS;
2020-12-24 07:42:56 +00:00
} else if (IS(s.p, s.n, "@preinit_array") ||
IS(s.p, s.n, "SHT_PREINIT_ARRAY")) {
2020-12-19 19:21:04 +00:00
return SHT_PREINIT_ARRAY;
2020-12-24 07:42:56 +00:00
} else if (IS(s.p, s.n, "@init_array") || IS(s.p, s.n, "SHT_INIT_ARRAY")) {
2020-12-19 19:21:04 +00:00
return SHT_INIT_ARRAY;
2020-12-24 07:42:56 +00:00
} else if (IS(s.p, s.n, "@fini_array") || IS(s.p, s.n, "SHT_FINI_ARRAY")) {
2020-12-19 19:21:04 +00:00
return SHT_FINI_ARRAY;
} else {
Fail(a, "unknown section type: %.*s", s.n, s.p);
}
}
2020-12-24 07:42:56 +00:00
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));
2020-12-28 01:05:03 +00:00
if (startswith(a->strings.p[name], ".text")) {
2020-12-19 19:21:04 +00:00
flags = SHF_ALLOC | SHF_EXECINSTR;
type = SHT_PROGBITS;
2020-12-28 01:05:03 +00:00
} else if (startswith(a->strings.p[name], ".data")) {
2020-12-19 19:21:04 +00:00
flags = SHF_ALLOC | SHF_WRITE;
type = SHT_PROGBITS;
2020-12-28 01:05:03 +00:00
} else if (startswith(a->strings.p[name], ".bss")) {
2020-12-19 19:21:04 +00:00
flags = SHF_ALLOC | SHF_WRITE;
type = SHT_NOBITS;
} else {
flags = SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE;
type = SHT_PROGBITS;
}
if (IsSlice(a, a->i)) {
2020-12-24 07:42:56 +00:00
flags = SectionFlags(a, GetSlice(a));
2020-12-19 19:21:04 +00:00
if (IsSlice(a, a->i)) {
2020-12-24 07:42:56 +00:00
type = SectionType(a, GetSlice(a));
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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) {
2020-12-19 19:21:04 +00:00
int fd;
struct stat st;
2020-12-24 07:42:56 +00:00
char *path, *path2;
struct Slice *data, arg;
arg = GetSlice(a);
2020-12-19 19:21:04 +00:00
path = strndup(arg.p, arg.n);
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
Fail(a, "not found: %s", path);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
free(path);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnType(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
int i;
i = GetSymbol(a, a->things.p[a->i++].i);
2020-12-24 07:42:56 +00:00
a->symbols.p[i].type = SymbolType(a, GetSlice(a));
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnSize(struct As *a, struct Slice s) {
2020-12-19 19:21:04 +00:00
int i;
i = GetSymbol(a, a->things.p[a->i++].i);
a->symbols.p[i].size = GetInt(a);
}
2020-12-25 00:01:48 +00:00
static void OpVisibility(struct As *a, int visibility) {
2020-12-19 19:21:04 +00:00
int i;
while (IsSlice(a, a->i)) {
i = GetSymbol(a, a->things.p[a->i++].i);
2020-12-25 00:01:48 +00:00
a->symbols.p[i].stv = visibility;
2020-12-19 19:21:04 +00:00
}
}
2020-12-25 00:01:48 +00:00
static void OnInternal(struct As *a, struct Slice s) {
OpVisibility(a, STV_INTERNAL);
}
2020-12-24 07:42:56 +00:00
static void OnHidden(struct As *a, struct Slice s) {
2020-12-25 00:01:48 +00:00
OpVisibility(a, STV_HIDDEN);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnProtected(struct As *a, struct Slice s) {
2020-12-25 00:01:48 +00:00
OpVisibility(a, STV_PROTECTED);
}
static void OpBind(struct As *a, int bind) {
2020-12-19 19:21:04 +00:00
int i;
while (IsSlice(a, a->i)) {
i = GetSymbol(a, a->things.p[a->i++].i);
2020-12-25 00:01:48 +00:00
a->symbols.p[i].stb = bind;
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
static void OnLocal(struct As *a, struct Slice s) {
2020-12-25 00:01:48 +00:00
OpBind(a, STB_LOCAL);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnWeak(struct As *a, struct Slice s) {
2020-12-25 00:01:48 +00:00
OpBind(a, STB_WEAK);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnGlobal(struct As *a, struct Slice s) {
2020-12-25 00:01:48 +00:00
OpBind(a, STB_GLOBAL);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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");
}
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static bool Prefix(struct As *a, const char *p, int n) {
int m, l, r;
unsigned long x, y;
2020-12-19 19:21:04 +00:00
if (n && n <= 8) {
2020-12-24 07:42:56 +00:00
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;
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
}
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);
2020-12-19 19:21:04 +00:00
l = 0;
r = ARRAYLEN(kRegs) - 1;
while (l <= r) {
m = (l + r) >> 1;
2020-12-24 07:42:56 +00:00
y = LOAD64BE(kRegs[m].s);
if (x < y) {
2020-12-19 19:21:04 +00:00
r = m - 1;
2020-12-24 07:42:56 +00:00
} else if (x > y) {
l = m + 1;
2020-12-19 19:21:04 +00:00
} else {
*out_reg = kRegs[m];
return true;
}
}
}
return false;
}
static int FindRegReg(struct Slice s) {
struct Reg reg;
if (!FindReg(s.p, s.n, &reg)) return -1;
return reg.reg;
}
static int FindRegRm(struct Slice s) {
struct Reg reg;
if (!FindReg(s.p, s.n, &reg)) return -1;
return reg.rm;
}
static int FindRegBase(struct Slice s) {
struct Reg reg;
if (!FindReg(s.p, s.n, &reg)) return -1;
return reg.base;
}
static int FindRegIndex(struct Slice s) {
struct Reg reg;
if (!FindReg(s.p, s.n, &reg)) return -1;
return reg.index;
}
2020-12-24 07:42:56 +00:00
static int RemoveRexw(int x) {
if (x == -1) return x;
x &= ~0x0800;
if (((x & 0xff00) >> 8) == REX) x &= ~0xff00;
return x;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static int GetRegisterReg(struct As *a) {
2020-12-19 21:39:09 +00:00
int reg;
struct Slice wut;
2020-12-24 07:42:56 +00:00
if ((reg = FindRegReg(GetSlice(a))) == -1) InvalidRegister(a);
2020-12-19 21:39:09 +00:00
return reg;
}
2020-12-24 07:42:56 +00:00
static int GetRegisterRm(struct As *a) {
2020-12-19 19:21:04 +00:00
int reg;
struct Slice wut;
2020-12-24 07:42:56 +00:00
if ((reg = FindRegRm(GetSlice(a))) == -1) InvalidRegister(a);
2020-12-19 19:21:04 +00:00
return reg;
}
2020-12-24 07:42:56 +00:00
static int ParseModrm(struct As *a, int *disp) {
/* ┌isreg
isrip
hasindex
hasbase
hasasz
rex
scale
index or size
base or reg
2020-12-19 19:21:04 +00:00
0b00000000000000000000000000000000*/
struct Slice str;
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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
}
}
2020-12-19 19:21:04 +00:00
if (!IsPunct(a, a->i, ')')) {
2020-12-24 07:42:56 +00:00
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, ')')) {
2020-12-28 19:38:38 +00:00
modrm |= (bsr(GetInt(a)) & 3) << 6;
2020-12-24 07:42:56 +00:00
}
} else {
modrm |= 4 << 3; // puttin' on the riz
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
ConsumePunct(a, ')');
}
if (modrm & HASASZ) {
EmitByte(a, ASZ);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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();
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void EmitModrm(struct As *a, int reg, int modrm, int disp) {
2020-12-19 21:39:09 +00:00
reg &= 7;
2020-12-19 19:21:04 +00:00
reg <<= 3;
2020-12-24 07:42:56 +00:00
if (modrm & ISREG) {
EmitByte(a, 0300 | reg | modrm & 7);
} else {
2020-12-25 00:01:48 +00:00
if (modrm & ISRIP) {
EmitByte(a, 005 | reg);
} else if (modrm & (HASBASE | HASINDEX)) {
EmitByte(a, 0204 | reg); // suboptimal
EmitByte(a, modrm);
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
EmitByte(a, 004 | reg);
EmitByte(a, 045);
2020-12-19 19:21:04 +00:00
}
2020-12-25 00:01:48 +00:00
EmitExpr(
a, disp,
a->pcrelative && ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX)))
? a->pcrelative
: R_X86_64_32S,
EmitLong);
2020-12-24 07:42:56 +00:00
}
}
static void EmitRex(struct As *a, int x) {
if (x & 0xff00) {
EmitByte(a, x >> 8);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
if (IsPunct(a, a->i, '$')) {
++a->i;
2020-12-24 07:42:56 +00:00
imm = Parse(a);
2020-12-19 21:39:09 +00:00
if (IsSlice(a, a->i)) { // imm -> reg
2020-12-19 19:21:04 +00:00
reg = GetRegisterRm(a);
switch ((reg & 070) >> 3) {
case 0:
2020-12-24 07:42:56 +00:00
EmitRex(a, reg);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xB0 + (reg & 7));
2020-12-24 07:42:56 +00:00
EmitExpr(a, imm, R_X86_64_8, EmitByte);
2020-12-19 19:21:04 +00:00
break;
case 1:
2020-12-24 07:42:56 +00:00
EmitRex(a, reg);
EmitByte(a, OSZ);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xB8 + (reg & 7));
2020-12-24 07:42:56 +00:00
EmitExpr(a, imm, R_X86_64_16, EmitWord);
2020-12-19 19:21:04 +00:00
break;
case 2:
2020-12-24 07:42:56 +00:00
EmitRex(a, reg);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xB8 + (reg & 7));
2020-12-24 07:42:56 +00:00
EmitExpr(a, imm, R_X86_64_32, EmitLong);
2020-12-19 19:21:04 +00:00
break;
case 3:
2020-12-24 07:42:56 +00:00
EmitRex(a, reg);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xB8 + (reg & 7)); // suboptimal
2020-12-24 07:42:56 +00:00
EmitExpr(a, imm, R_X86_64_64, EmitQuad);
2020-12-19 19:21:04 +00:00
break;
default:
Fail(a, "todo movd/movq");
}
2020-12-24 07:42:56 +00:00
} else { // imm -> modrm
modrm = ParseModrm(a, &disp);
switch (GetOpSize(a, s, modrm, 1)) {
2020-12-19 19:21:04 +00:00
case 0:
2020-12-24 07:42:56 +00:00
EmitRex(a, modrm);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xC6);
2020-12-24 07:42:56 +00:00
EmitModrm(a, 0, modrm, disp);
EmitExpr(a, imm, R_X86_64_8, EmitByte);
2020-12-19 19:21:04 +00:00
break;
case 1:
2020-12-24 07:42:56 +00:00
EmitByte(a, OSZ);
EmitRex(a, modrm);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xC7);
2020-12-24 07:42:56 +00:00
EmitModrm(a, 0, modrm, disp);
EmitExpr(a, imm, R_X86_64_16, EmitWord);
2020-12-19 19:21:04 +00:00
break;
case 2:
2020-12-24 07:42:56 +00:00
EmitRex(a, modrm);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xC7);
2020-12-24 07:42:56 +00:00
EmitModrm(a, 0, modrm, disp);
EmitExpr(a, imm, R_X86_64_32, EmitLong);
2020-12-19 19:21:04 +00:00
break;
case 3:
2020-12-24 07:42:56 +00:00
EmitRex(a, modrm | REXW << 8);
2020-12-28 19:38:38 +00:00
EmitByte(a, 0xC7); // suboptimal
2020-12-24 07:42:56 +00:00
EmitModrm(a, 0, modrm, disp);
EmitExpr(a, imm, R_X86_64_32, EmitLong);
2020-12-19 19:21:04 +00:00
break;
default:
2020-12-24 07:42:56 +00:00
abort();
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
} else if (IsSlice(a, a->i)) { // reg -> reg/modrm
2020-12-19 21:39:09 +00:00
reg = GetRegisterReg(a);
2020-12-24 07:42:56 +00:00
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x88, reg, modrm, disp, 1);
} else { // modrm -> reg
modrm = ParseModrm(a, &disp);
2020-12-19 21:39:09 +00:00
reg = GetRegisterReg(a);
2020-12-24 07:42:56 +00:00
EmitRexOpModrm(a, 0x8A, reg, modrm, disp, 1);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
if (IsPunct(a, a->i, '$')) {
++a->i;
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
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;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
modrm = ParseModrm(a, &disp);
reg = GetOpSize(a, opname, modrm, 1) << 3 | op;
EmitRexOpModrm(a, 0xC0, reg, modrm, disp, 1); // suboptimal
EmitByte(a, imm);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static noinline void OpBsu(struct As *a, struct Slice opname, int op) {
OpBsuImpl(a, opname, op);
2020-12-19 19:21:04 +00:00
}
2020-12-28 01:05:03 +00:00
static noinline int OpF6Impl(struct As *a, struct Slice s, int reg) {
2020-12-24 07:42:56 +00:00
int modrm, imm, disp;
modrm = ParseModrm(a, &disp);
reg |= GetOpSize(a, s, modrm, 1) << 3;
EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1);
return reg;
}
2020-12-28 01:05:03 +00:00
static noinline int OpF6(struct As *a, struct Slice s, int reg) {
return OpF6Impl(a, s, reg);
}
2020-12-24 07:42:56 +00:00
static void OnTest(struct As *a, struct Slice s) {
int reg, modrm, imm, disp;
2020-12-19 19:21:04 +00:00
if (IsPunct(a, a->i, '$')) {
++a->i;
2020-12-24 07:42:56 +00:00
imm = Parse(a);
reg = OpF6(a, s, 0); // suboptimal
EmitImm(a, reg, imm);
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
reg = GetRegisterReg(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x84, reg, modrm, disp, 1);
2020-12-19 19:21:04 +00:00
}
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnShrd(struct As *a, struct Slice s) {
OpShrld(a, s, 0xAC);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnShld(struct As *a, struct Slice s) {
OpShrld(a, s, 0xA4);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
}
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OpMovdqx(struct As *a, int op) {
OpSseMov(a, op + 0x10, op);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovdqu(struct As *a, struct Slice s) {
EmitByte(a, 0xF3);
OpMovdqx(a, 0x0F6F);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovups(struct As *a, struct Slice s) {
OpSseMov(a, 0x0F11, 0x0F10);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovupd(struct As *a, struct Slice s) {
EmitByte(a, 0x66);
OnMovups(a, s);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovdqa(struct As *a, struct Slice s) {
EmitByte(a, 0x66);
OpMovdqx(a, 0x0F6F);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovaps(struct As *a, struct Slice s) {
OpSseMov(a, 0x0F29, 0x0F28);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovapd(struct As *a, struct Slice s) {
EmitByte(a, 0x66);
OpSseMov(a, 0x0F29, 0x0F28);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovss(struct As *a, struct Slice s) {
OpSseMov(a, 0xF30F11, 0xF30F10);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static void OnMovsd(struct As *a, struct Slice s) {
OpSseMov(a, 0xF20F11, 0xF20F10);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static bool IsSsePrefix(int c) {
return c == 0x66 || c == 0xF2 || c == 0xF3; // must come before rex
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static noinline void OpSse(struct As *a, int op) {
OpSseImpl(a, op);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
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);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static noinline void OpSseIb(struct As *a, int op) {
OpSseIbImpl(a, op);
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
static bool HasXmmOnLine(struct As *a) {
2020-12-19 19:21:04 +00:00
int i;
2020-12-24 07:42:56 +00:00
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 &&
2020-12-28 01:05:03 +00:00
(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"))) {
2020-12-24 07:42:56 +00:00
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)) {
2020-12-25 00:01:48 +00:00
if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX;
2020-12-24 07:42:56 +00:00
EmitRexOpModrm(a, 0xFF, 2, modrm, disp, 0);
2020-12-25 00:01:48 +00:00
a->pcrelative = 0;
2020-12-24 07:42:56 +00:00
} 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) {
2020-12-25 00:01:48 +00:00
if ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) {
modrm |= ISRIP;
a->pcrelative = R_X86_64_GOTPCRELX;
}
2020-12-24 07:42:56 +00:00
EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0);
2020-12-25 00:01:48 +00:00
a->pcrelative = 0;
2020-12-24 07:42:56 +00:00
} 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 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);
}
static noinline void OpFcomImpl(struct As *a, int op) {
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");
EmitVarword(a, op | rm & 7);
}
static noinline void OpFcom(struct As *a, int op) {
OpFcomImpl(a, op);
}
2020-12-24 07:42:56 +00:00
// 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); }
2020-12-24 07:42:56 +00:00
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); }
2020-12-24 07:42:56 +00:00
static void OnFadds(struct As *a, struct Slice s) { OpFpu1(a, 0xD8, 0); }
static void OnFchs(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E0); }
static void OnFcmovb(struct As *a, struct Slice s) { OpFcom(a, 0xDAC0); }
static void OnFcmovbe(struct As *a, struct Slice s) { OpFcom(a, 0xDAD0); }
static void OnFcmove(struct As *a, struct Slice s) { OpFcom(a, 0xDAC8); }
static void OnFcmovnb(struct As *a, struct Slice s) { OpFcom(a, 0xDBC0); }
static void OnFcmovnbe(struct As *a, struct Slice s) { OpFcom(a, 0xDBD0); }
static void OnFcmovne(struct As *a, struct Slice s) { OpFcom(a, 0xDBC8); }
static void OnFcmovnu(struct As *a, struct Slice s) { OpFcom(a, 0xDBD8); }
static void OnFcmovu(struct As *a, struct Slice s) { OpFcom(a, 0xDAD8); }
static void OnFcomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBF0); }
static void OnFcomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFF0); }
static void OnFdivrp(struct As *a, struct Slice s) { EmitVarword(a, 0xDEF9); }
2020-12-24 07:42:56 +00:00
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 OnFucomi(struct As *a, struct Slice s) { OpFcom(a, 0xDBE8); }
static void OnFucomip(struct As *a, struct Slice s) { OpFcom(a, 0xDFE8); }
2020-12-24 07:42:56 +00:00
static void OnFwait(struct As *a, struct Slice s) { EmitByte(a, 0x9B); }
static void OnFxam(struct As *a, struct Slice s) { EmitVarword(a, 0xD9E5); }
static void OnFxtract(struct As *a, struct Slice s) { EmitVarword(a, 0xD9F4); }
2020-12-24 07:42:56 +00:00
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}, //
{"fcmovb", OnFcmovb}, //
{"fcmovbe", OnFcmovbe}, //
{"fcmove", OnFcmove}, //
{"fcmovnb", OnFcmovnb}, //
{"fcmovnbe", OnFcmovnbe}, //
{"fcmovne", OnFcmovne}, //
{"fcmovnu", OnFcmovnu}, //
{"fcmovu", OnFcmovu}, //
{"fcomi", OnFcomi}, //
2020-12-24 07:42:56 +00:00
{"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}, //
{"fxtract", OnFxtract}, //
2020-12-24 07:42:56 +00:00
{"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);
2020-12-19 19:21:04 +00:00
return true;
}
}
}
return false;
}
2020-12-24 07:42:56 +00:00
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) {
2020-12-19 19:21:04 +00:00
struct Slice s;
for (;;) {
2020-12-24 07:42:56 +00:00
s = GetSlice(a);
if (Prefix(a, s.p, s.n)) {
if (IsPunct(a, a->i, ';')) {
return;
}
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
break;
}
}
if (!OnDirective8(a, s)) {
if (!OnDirective16(a, s)) {
Fail(a, "unexpected op: %.*s", s.n, s.p);
2020-12-19 19:21:04 +00:00
}
}
ConsumePunct(a, ';');
}
2020-12-24 07:42:56 +00:00
static void Assemble(struct As *a) {
2020-12-19 19:21:04 +00:00
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, ':')) {
2020-12-24 07:42:56 +00:00
OnSymbol(a, a->things.p[a->i].i);
2020-12-19 19:21:04 +00:00
} else {
2020-12-24 07:42:56 +00:00
OnDirective(a);
2020-12-19 19:21:04 +00:00
}
break;
case TT_INT:
if (IsPunct(a, a->i + 1, ':')) {
2020-12-24 07:42:56 +00:00
OnLocalLabel(a, a->ints.p[a->things.p[a->i].i]);
break;
2020-12-19 19:21:04 +00:00
}
2020-12-24 07:42:56 +00:00
Fail(a, "unexpected token");
2020-12-19 19:21:04 +00:00
default:
Fail(a, "unexpected token");
}
}
}
2020-12-24 07:42:56 +00:00
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:
2020-12-26 10:09:07 +00:00
Fail(a, "this corruption %d", a->things.p[i].t);
2020-12-24 07:42:56 +00:00
}
}
static void EvaluateExpr(struct As *a, int i) {
if (i == -1) return;
if (a->exprs.p[i].isevaluated) return;
if (a->exprs.p[i].isvisited) Fail(a, "circular expr");
a->exprs.p[i].isvisited = true;
EvaluateExpr(a, a->exprs.p[i].lhs);
EvaluateExpr(a, a->exprs.p[i].rhs);
a->i = a->exprs.p[i].tok;
switch (a->exprs.p[i].kind) {
case EX_INT:
break;
case EX_SYM:
a->exprs.p[i].x = ResolveSymbol(a, a->exprs.p[i].x);
break;
default:
break;
}
a->exprs.p[i].isevaluated = true;
}
static void Write32(char b[4], int x) {
b[0] = x >> 000;
b[1] = x >> 010;
b[2] = x >> 020;
b[3] = x >> 030;
}
static void MarkUsedSymbols(struct As *a, int i) {
if (i == -1) return;
MarkUsedSymbols(a, a->exprs.p[i].lhs);
MarkUsedSymbols(a, a->exprs.p[i].rhs);
if (a->exprs.p[i].kind == EX_SYM) {
a->symbols.p[a->exprs.p[i].x].isused = true;
}
}
static void Evaluate(struct As *a) {
int i;
struct Expr *e;
for (i = 0; i < a->relas.n; ++i) {
EvaluateExpr(a, a->relas.p[i].expr);
if (a->relas.p[i].kind == R_X86_64_PC32) {
e = a->exprs.p + a->relas.p[i].expr;
if (e->kind == EX_SYM && a->symbols.p[e->x].stb == STB_LOCAL &&
a->symbols.p[e->x].section == a->relas.p[i].section) {
a->relas.p[i].isdead = true;
Write32((a->sections.p[a->relas.p[i].section].binary.p +
a->relas.p[i].offset),
(a->symbols.p[e->x].offset - a->relas.p[i].offset +
a->relas.p[i].addend));
}
}
}
for (i = 0; i < a->relas.n; ++i) {
if (a->relas.p[i].isdead) continue;
MarkUsedSymbols(a, a->relas.p[i].expr);
}
}
2020-12-26 10:09:07 +00:00
static void MarkUndefinedSymbolsGlobal(struct As *a) {
int i;
for (i = 0; i < a->symbols.n; ++i) {
if (a->symbols.p[i].isused && !a->symbols.p[i].section &&
a->symbols.p[i].stb == STB_LOCAL) {
a->symbols.p[i].stb = STB_GLOBAL;
}
}
}
2020-12-24 07:42:56 +00:00
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) {
2020-12-26 10:09:07 +00:00
char *p;
int i, j, s, e;
2020-12-19 19:21:04 +00:00
struct ElfWriter *elf;
2020-12-24 07:42:56 +00:00
elf = elfwriter_open(a->strings.p[path], 0644);
for (i = 0; i < a->symbols.n; ++i) {
if (!IsLiveSymbol(a, i)) continue;
2020-12-26 10:09:07 +00:00
p = strndup(a->slices.p[a->symbols.p[i].name].p,
a->slices.p[a->symbols.p[i].name].n);
2020-12-24 07:42:56 +00:00
a->symbols.p[i].ref = elfwriter_appendsym(
2020-12-26 10:09:07 +00:00
elf, p, ELF64_ST_INFO(a->symbols.p[i].stb, a->symbols.p[i].type),
2020-12-24 07:42:56 +00:00
a->symbols.p[i].stv, a->symbols.p[i].offset, a->symbols.p[i].size);
2020-12-26 10:09:07 +00:00
free(p);
2020-12-24 07:42:56 +00:00
}
2020-12-19 19:21:04 +00:00
for (i = 0; i < a->sections.n; ++i) {
elfwriter_align(elf, a->sections.p[i].align, 0);
2020-12-24 07:42:56 +00:00
s = elfwriter_startsection(elf, a->strings.p[a->sections.p[i].name],
a->sections.p[i].type, a->sections.p[i].flags);
2020-12-19 19:21:04 +00:00
for (j = 0; j < a->symbols.n; ++j) {
2020-12-24 07:42:56 +00:00
if (!IsLiveSymbol(a, j)) continue;
2020-12-19 19:21:04 +00:00
if (a->symbols.p[j].section != i) continue;
2020-12-24 07:42:56 +00:00
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;
2020-12-26 10:09:07 +00:00
e = a->relas.p[j].expr;
a->i = a->exprs.p[e].tok;
switch (a->exprs.p[e].kind) {
2020-12-24 07:42:56 +00:00
case EX_INT:
break;
case EX_SYM:
2020-12-26 10:09:07 +00:00
elfwriter_appendrela(elf, a->relas.p[j].offset,
a->symbols.p[a->exprs.p[e].x].ref,
a->relas.p[j].kind, a->relas.p[j].addend);
2020-12-24 07:42:56 +00:00
break;
case EX_ADD:
2020-12-26 10:09:07 +00:00
if (a->exprs.p[a->exprs.p[e].lhs].kind == EX_SYM &&
a->exprs.p[a->exprs.p[e].rhs].kind == EX_INT) {
2020-12-24 07:42:56 +00:00
elfwriter_appendrela(
elf, a->relas.p[j].offset,
2020-12-26 10:09:07 +00:00
a->symbols.p[a->exprs.p[a->exprs.p[e].lhs].x].ref,
2020-12-24 07:42:56 +00:00
a->relas.p[j].kind,
2020-12-26 10:09:07 +00:00
a->relas.p[j].addend + a->exprs.p[a->exprs.p[e].rhs].x);
2020-12-24 07:42:56 +00:00
} else {
Fail(a, "bad addend");
}
break;
default:
Fail(a, "unsupported relocation type");
}
2020-12-19 19:21:04 +00:00
}
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);
}
2020-12-26 10:09:07 +00:00
static void CheckIntegrity(struct As *a) {
int i;
for (i = 0; i < a->things.n; ++i) {
CHECK_LT((int)a->things.p[i].s, a->sauces.n);
switch (a->things.p[i].t) {
case TT_INT:
case TT_FORWARD:
case TT_BACKWARD:
CHECK_LT(a->things.p[i].i, a->ints.n);
break;
case TT_FLOAT:
CHECK_LT(a->things.p[i].i, a->floats.n);
break;
case TT_SLICE:
CHECK_LT(a->things.p[i].i, a->slices.n);
break;
default:
break;
}
}
for (i = 0; i < a->sections.n; ++i) {
CHECK_LT(a->sections.p[i].name, a->strings.n);
}
for (i = 0; i < a->symbols.n; ++i) {
CHECK_LT(a->symbols.p[i].name, a->slices.n);
CHECK_LT(a->symbols.p[i].section, a->sections.n);
}
for (i = 0; i < a->labels.n; ++i) {
CHECK_LT(a->labels.p[i].tok, a->things.n);
CHECK_LT(a->labels.p[i].symbol, a->symbols.n);
}
for (i = 0; i < a->relas.n; ++i) {
CHECK_LT(a->relas.p[i].expr, a->exprs.n);
CHECK_LT(a->relas.p[i].section, a->sections.n);
}
for (i = 0; i < a->exprs.n; ++i) {
CHECK_LT(a->exprs.p[i].tok, a->things.n);
if (a->exprs.p[i].lhs != -1) CHECK_LT(a->exprs.p[i].lhs, a->exprs.n);
if (a->exprs.p[i].rhs != -1) CHECK_LT(a->exprs.p[i].rhs, a->exprs.n);
switch (a->exprs.p[i].kind) {
case EX_SYM:
CHECK_LT(a->exprs.p[i].x, a->things.n);
CHECK(a->things.p[a->exprs.p[i].x].t == TT_SLICE ||
a->things.p[a->exprs.p[i].x].t == TT_FORWARD ||
a->things.p[a->exprs.p[i].x].t == TT_BACKWARD);
break;
default:
break;
}
}
}
2020-12-24 07:42:56 +00:00
static void PrintThings(struct As *a) {
2020-12-19 19:21:04 +00:00
int i;
2020-12-24 07:42:56 +00:00
char pbuf[4], fbuf[32];
2020-12-19 19:21:04 +00:00
for (i = 0; i < a->things.n; ++i) {
2020-12-24 07:42:56 +00:00
printf("%s:%d:: ", a->strings.p[a->sauces.p[a->things.p[i].s].path],
2020-12-19 19:21:04 +00:00
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:
2020-12-24 07:42:56 +00:00
printf("TT_SLICE %.*s\n", a->slices.p[a->things.p[i].i].n,
2020-12-19 19:21:04 +00:00
a->slices.p[a->things.p[i].i].p);
break;
case TT_PUNCT:
2020-12-24 07:42:56 +00:00
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]);
2020-12-19 19:21:04 +00:00
break;
default:
2020-12-24 07:42:56 +00:00
abort();
2020-12-19 19:21:04 +00:00
}
}
}
void Assembler(int argc, char *argv[]) {
2020-12-24 07:42:56 +00:00
struct As *a;
2020-12-19 19:21:04 +00:00
a = NewAssembler();
2020-12-24 07:42:56 +00:00
ReadFlags(a, argc, argv);
SaveString(&a->incpaths, strdup("."));
2020-12-28 01:05:03 +00:00
SaveString(&a->incpaths, xdirname(a->strings.p[a->inpath]));
2020-12-24 07:42:56 +00:00
Tokenize(a, a->inpath);
2020-12-19 19:21:04 +00:00
/* PrintThings(a); */
Assemble(a);
2020-12-26 10:09:07 +00:00
/* CheckIntegrity(a); */
2020-12-24 07:42:56 +00:00
Evaluate(a);
2020-12-25 00:01:48 +00:00
MarkUndefinedSymbolsGlobal(a);
2020-12-24 07:42:56 +00:00
Objectify(a, a->outpath);
2020-12-26 10:09:07 +00:00
/* malloc_stats(); */
2020-12-24 07:42:56 +00:00
FreeAssembler(a);
2020-12-19 19:21:04 +00:00
}
int main(int argc, char *argv[]) {
2020-12-24 07:42:56 +00:00
showcrashreports();
if (argc == 1) {
2020-12-26 10:09:07 +00:00
system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s");
2020-12-24 07:42:56 +00:00
system("objdump -xwd /tmp/o");
exit(0);
}
2020-12-19 19:21:04 +00:00
Assembler(argc, argv);
return 0;
}