Create integrated assembler for chibicc

All we need now to complete the triforce is an integrated linker. That
way Cosmpolitan will let C be a "build anywhere run anywhere" language.
This commit is contained in:
Justine Tunney 2020-12-29 22:40:59 -08:00
parent 5eddadafbd
commit 81ef162703
6 changed files with 267 additions and 88 deletions

View file

@ -445,6 +445,7 @@ static unsigned Hash(const void *p, unsigned long n) {
static bool IsPunctMergeable(int c) {
switch (c) {
case ',':
case ';':
case '$':
return false;
@ -710,7 +711,7 @@ static void Tokenize(struct As *a, int path) {
}
bol = false;
if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' ||
c == '\v' || c == ',') {
c == '\v') {
++p;
continue;
}
@ -960,6 +961,12 @@ static bool IsForward(struct As *a, int i) {
static bool IsBackward(struct As *a, int i) {
return a->things.p[i].t == TT_BACKWARD;
}
static bool IsComma(struct As *a) {
return IsPunct(a, a->i, ',');
}
static bool IsSemicolon(struct As *a) {
return IsPunct(a, a->i, ';');
}
static bool IsRegister(struct As *a, int i) {
return IsSlice(a, i) && (a->slices.p[a->things.p[i].i].n &&
@ -975,6 +982,10 @@ static void ConsumePunct(struct As *a, int c) {
}
}
static void ConsumeComma(struct As *a) {
ConsumePunct(a, ',');
}
static int NewPrimary(struct As *a, enum ExprKind k, long x) {
AppendExpr(a);
a->exprs.p[a->exprs.n - 1].kind = k;
@ -1374,7 +1385,7 @@ static void EmitVarword(struct As *a, unsigned long x) {
static void OnSleb128(struct As *a, struct Slice s) {
int c;
long x;
while (!IsPunct(a, a->i, ';')) {
for (;;) {
x = GetInt(a);
for (;;) {
c = x & 0x7f;
@ -1385,6 +1396,8 @@ static void OnSleb128(struct As *a, struct Slice s) {
c |= 0x80;
}
EmitByte(a, c);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
}
@ -1392,7 +1405,7 @@ static void OnSleb128(struct As *a, struct Slice s) {
static void OnUleb128(struct As *a, struct Slice s) {
int c;
unsigned long x;
while (!IsPunct(a, a->i, ';')) {
for (;;) {
x = GetInt(a);
do {
c = x & 0x7f;
@ -1400,25 +1413,36 @@ static void OnUleb128(struct As *a, struct Slice s) {
if (x) c |= 0x80;
EmitByte(a, c);
} while (x);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
static void OnZero(struct As *a, struct Slice s) {
long n;
char *p;
while (IsInt(a, a->i)) {
for (;;) {
n = GetInt(a);
p = calloc(n, 1);
EmitData(a, p, n);
free(p);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
static void OnSpace(struct As *a, struct Slice s) {
long n;
char *p;
int fill;
p = malloc((n = GetInt(a)));
memset(p, IsInt(a, a->i) ? GetInt(a) : 0, n);
if (IsComma(a)) {
ConsumeComma(a);
fill = GetInt(a);
} else {
fill = 0;
}
memset(p, fill, n);
EmitData(a, p, n);
free(p);
}
@ -1455,28 +1479,29 @@ static void EmitExpr(struct As *a, int expr, int kind,
}
}
static void OpInt(struct As *a, int kind,
void emitter(struct As *, unsigned long)) {
for (;;) {
EmitExpr(a, Parse(a), kind, emitter);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
static void OnByte(struct As *a, struct Slice s) {
do {
EmitExpr(a, Parse(a), R_X86_64_8, EmitByte);
} while (!IsPunct(a, a->i, ';'));
OpInt(a, R_X86_64_8, EmitByte);
}
static void OnWord(struct As *a, struct Slice s) {
do {
EmitExpr(a, Parse(a), R_X86_64_16, EmitWord);
} while (!IsPunct(a, a->i, ';'));
OpInt(a, R_X86_64_16, EmitWord);
}
static void OnLong(struct As *a, struct Slice s) {
do {
EmitExpr(a, Parse(a), R_X86_64_32, EmitLong);
} while (!IsPunct(a, a->i, ';'));
OpInt(a, R_X86_64_32, EmitLong);
}
static void OnQuad(struct As *a, struct Slice s) {
do {
EmitExpr(a, Parse(a), R_X86_64_64, EmitQuad);
} while (!IsPunct(a, a->i, ';'));
OpInt(a, R_X86_64_64, EmitQuad);
}
static void OnFloat(struct As *a, struct Slice s) {
@ -1485,13 +1510,13 @@ static void OnFloat(struct As *a, struct Slice s) {
for (;;) {
if (IsFloat(a, a->i)) {
f = GetFloat(a);
} else if (IsInt(a, a->i)) {
f = GetInt(a);
} else {
break;
f = GetInt(a);
}
memcpy(b, &f, 4);
EmitData(a, b, 4);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1501,13 +1526,13 @@ static void OnDouble(struct As *a, struct Slice s) {
for (;;) {
if (IsFloat(a, a->i)) {
f = GetFloat(a);
} else if (IsInt(a, a->i)) {
f = GetInt(a);
} else {
break;
f = GetInt(a);
}
memcpy(b, &f, 8);
EmitData(a, b, 8);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1517,14 +1542,14 @@ static void OnLongDouble(struct As *a, int n) {
for (;;) {
if (IsFloat(a, a->i)) {
f = GetFloat(a);
} else if (IsInt(a, a->i)) {
f = GetInt(a);
} else {
break;
f = GetInt(a);
}
memset(b, 0, 16);
memcpy(b, &f, sizeof(f));
EmitData(a, b, n);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1538,18 +1563,22 @@ static void OnLdbl(struct As *a, struct Slice s) {
static void OnAscii(struct As *a, struct Slice s) {
struct Slice arg;
while (IsSlice(a, a->i)) {
for (;;) {
arg = GetSlice(a);
EmitData(a, arg.p, arg.n);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
static void OnAsciz(struct As *a, struct Slice s) {
struct Slice arg;
while (IsSlice(a, a->i)) {
for (;;) {
arg = GetSlice(a);
EmitData(a, arg.p, arg.n);
EmitByte(a, 0);
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1597,9 +1626,11 @@ static void OnAlign(struct As *a, struct Slice s) {
if (__builtin_popcountl(align) != 1) Fail(a, "alignment not power of 2");
fill = (a->sections.p[a->section].flags & SHF_EXECINSTR) ? 0x90 : 0;
maxskip = 268435456;
if (IsInt(a, a->i)) {
if (IsComma(a)) {
++a->i;
fill = GetInt(a);
if (IsInt(a, a->i)) {
if (IsComma(a)) {
++a->i;
maxskip = GetInt(a);
}
}
@ -1700,9 +1731,11 @@ static void OnSection(struct As *a, struct Slice s) {
flags = SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE;
type = SHT_PROGBITS;
}
if (IsSlice(a, a->i)) {
if (IsComma(a)) {
++a->i;
flags = SectionFlags(a, GetSlice(a));
if (IsSlice(a, a->i)) {
if (IsComma(a)) {
++a->i;
type = SectionType(a, GetSlice(a));
}
}
@ -1761,20 +1794,24 @@ static void OnIncbin(struct As *a, struct Slice s) {
static void OnType(struct As *a, struct Slice s) {
int i;
i = GetSymbol(a, a->things.p[a->i++].i);
ConsumeComma(a);
a->symbols.p[i].type = SymbolType(a, GetSlice(a));
}
static void OnSize(struct As *a, struct Slice s) {
int i;
i = GetSymbol(a, a->things.p[a->i++].i);
ConsumeComma(a);
a->symbols.p[i].size = GetInt(a);
}
static void OpVisibility(struct As *a, int visibility) {
int i;
while (IsSlice(a, a->i)) {
for (;;) {
i = GetSymbol(a, a->things.p[a->i++].i);
a->symbols.p[i].stv = visibility;
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1792,9 +1829,11 @@ static void OnProtected(struct As *a, struct Slice s) {
static void OpBind(struct As *a, int bind) {
int i;
while (IsSlice(a, a->i)) {
for (;;) {
i = GetSymbol(a, a->things.p[a->i++].i);
a->symbols.p[i].stb = bind;
if (IsSemicolon(a)) break;
ConsumeComma(a);
}
}
@ -1975,6 +2014,7 @@ static int ParseModrm(struct As *a, int *disp) {
index or size
base or reg
000100000000000100101
0b00000000000000000000000000000000*/
struct Slice str;
int reg, scale, modrm = 0;
@ -1989,7 +2029,8 @@ static int ParseModrm(struct As *a, int *disp) {
}
if (IsPunct(a, a->i, '(')) {
++a->i;
if ((str = GetSlice(a)).n) {
if (!IsComma(a)) {
str = GetSlice(a);
modrm |= HASBASE;
if (!strncasecmp(str.p, "%rip", str.n)) {
modrm |= ISRIP;
@ -2001,18 +2042,18 @@ static int ParseModrm(struct As *a, int *disp) {
if (((reg & 070) >> 3) == 2) modrm |= HASASZ; // asz
}
}
if (!IsPunct(a, a->i, ')')) {
if (IsComma(a)) {
++a->i;
modrm |= HASINDEX;
reg = FindRegIndex(GetSlice(a));
if (reg == -1) InvalidRegister(a);
modrm |= (reg & 007) << 3; // index
modrm |= reg & 0xff00; // rex
if (((reg & 070) >> 3) == 2) modrm |= HASASZ; // asz
if (!IsPunct(a, a->i, ')')) {
if (IsComma(a)) {
++a->i;
modrm |= (bsr(GetInt(a)) & 3) << 6;
}
} else {
modrm |= 4 << 3; // puttin' on the riz
}
ConsumePunct(a, ')');
}
@ -2041,6 +2082,8 @@ static void EmitImm(struct As *a, int reg, int imm) {
}
static void EmitModrm(struct As *a, int reg, int modrm, int disp) {
int relo, mod, rm;
void (*emitter)(struct As *, unsigned long);
reg &= 7;
reg <<= 3;
if (modrm & ISREG) {
@ -2048,19 +2091,54 @@ static void EmitModrm(struct As *a, int reg, int modrm, int disp) {
} else {
if (modrm & ISRIP) {
EmitByte(a, 005 | reg);
emitter = EmitLong;
relo = a->pcrelative ?: R_X86_64_PC32;
} else if (modrm & (HASBASE | HASINDEX)) {
EmitByte(a, 0204 | reg); // suboptimal
EmitByte(a, modrm);
if (disp == -1) {
emitter = NULL;
relo = 0;
mod = 0;
} else if (a->exprs.p[disp].kind == EX_INT) {
if (!a->exprs.p[disp].x) {
emitter = NULL;
relo = 0;
mod = 0;
} else if (-128 <= a->exprs.p[disp].x && a->exprs.p[disp].x <= 127) {
emitter = EmitByte;
relo = R_X86_64_32S;
mod = 0100;
} else {
EmitByte(a, 004 | reg);
EmitByte(a, 045);
emitter = EmitLong;
relo = R_X86_64_32S;
mod = 0200;
}
} else {
emitter = EmitLong;
relo = R_X86_64_32S;
mod = 0200;
}
if (!(modrm & HASINDEX) && (modrm & 7) != 4) {
EmitByte(a, mod | reg | modrm);
} else if (!(modrm & HASINDEX) && (modrm & 7) == 4) {
EmitByte(a, mod | reg | 4); // (%rsp) must be (%rsp,%riz)
EmitByte(a, 040 | modrm);
} else if (!mod && (modrm & 7) == 5) {
EmitByte(a, 0100 | reg | 4); // (%rbp,𝑥) is special
EmitByte(a, modrm);
EmitByte(a, 0);
} else {
EmitByte(a, mod | reg | 4);
EmitByte(a, modrm);
}
} else {
EmitByte(a, 004 | reg); // (%rbp,%riz) is disp32
EmitByte(a, 045);
emitter = EmitLong;
relo = R_X86_64_32S;
}
if (emitter) {
EmitExpr(a, disp, relo, emitter);
}
EmitExpr(
a, disp,
a->pcrelative && ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX)))
? a->pcrelative
: R_X86_64_32S,
EmitLong);
}
}
@ -2078,7 +2156,6 @@ static void EmitOpModrm(struct As *a, long op, int reg, int modrm, int disp,
EmitModrm(a, reg, modrm, disp);
break;
case 1:
EmitByte(a, OSZ);
EmitVarword(a, op + skew);
EmitModrm(a, reg, modrm, disp);
break;
@ -2095,6 +2172,7 @@ static void EmitOpModrm(struct As *a, long op, int reg, int modrm, int disp,
static void EmitRexOpModrm(struct As *a, long op, int reg, int modrm, int disp,
int skew) {
if (((reg & 070) >> 3) == 1) EmitByte(a, OSZ);
EmitRex(a, reg | modrm);
EmitOpModrm(a, op, reg, modrm, disp, skew);
}
@ -2102,6 +2180,7 @@ static void EmitRexOpModrm(struct As *a, long op, int reg, int modrm, int disp,
static void OnLea(struct As *a, struct Slice s) {
int modrm, reg, disp;
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, 0x8D, reg, modrm, disp, 0);
}
@ -2111,6 +2190,7 @@ static void OnMov(struct As *a, struct Slice s) {
if (IsPunct(a, a->i, '$')) {
++a->i;
imm = Parse(a);
ConsumeComma(a);
if (IsSlice(a, a->i)) { // imm -> reg
reg = GetRegisterRm(a);
switch ((reg & 070) >> 3) {
@ -2120,8 +2200,8 @@ static void OnMov(struct As *a, struct Slice s) {
EmitExpr(a, imm, R_X86_64_8, EmitByte);
break;
case 1:
EmitRex(a, reg);
EmitByte(a, OSZ);
EmitRex(a, reg);
EmitByte(a, 0xB8 + (reg & 7));
EmitExpr(a, imm, R_X86_64_16, EmitWord);
break;
@ -2172,10 +2252,12 @@ static void OnMov(struct As *a, struct Slice s) {
}
} else if (IsSlice(a, a->i)) { // reg -> reg/modrm
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x88, reg, modrm, disp, 1);
} else { // modrm -> reg
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, 0x8A, reg, modrm, disp, 1);
}
@ -2184,6 +2266,7 @@ static void OnMov(struct As *a, struct Slice s) {
static void EmitMovx(struct As *a, struct Slice opname, int op) {
int reg, modrm, disp;
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRex(a, reg);
if (((reg & 070) >> 3) == 1) EmitByte(a, OSZ);
@ -2202,6 +2285,7 @@ static void OnMovsbwx(struct As *a, struct Slice s) {
static void OnMovslq(struct As *a, struct Slice s) {
int reg, modrm, disp;
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitByte(a, REXW);
EmitByte(a, 0x63);
@ -2213,16 +2297,19 @@ static noinline void OpAluImpl(struct As *a, struct Slice opname, int op) {
if (IsPunct(a, a->i, '$')) { // imm -> reg/modrm
++a->i;
imm = Parse(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
reg = GetOpSize(a, opname, modrm, 1) << 3 | op;
EmitRexOpModrm(a, 0x80, reg, modrm, disp, 1); // suboptimal
EmitImm(a, reg, imm);
} else if (IsSlice(a, a->i)) { // reg -> reg/modrm
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, op << 3, reg, modrm, disp, 1);
} else { // modrm -> reg
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, op << 3 | 2, reg, modrm, disp, 1);
}
@ -2237,14 +2324,16 @@ static noinline void OpBsuImpl(struct As *a, struct Slice opname, int op) {
if (IsPunct(a, a->i, '$')) {
++a->i;
imm = Parse(a);
ConsumeComma(a);
} else if (IsSlice(a, a->i) &&
(a->slices.p[a->things.p[a->i].i].n == 3 &&
!strncasecmp(a->slices.p[a->things.p[a->i].i].p, "%cl", 3)) &&
!IsPunct(a, a->i + 1, ';')) {
++a->i;
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
reg = GetOpSize(a, opname, modrm, 1) << 3 | op;
EmitRexOpModrm(a, 0xC0, reg, modrm, disp, 1);
EmitRexOpModrm(a, 0xD2, reg, modrm, disp, 1);
return;
} else {
AppendExpr(a);
@ -2256,7 +2345,7 @@ static noinline void OpBsuImpl(struct As *a, struct Slice opname, int op) {
modrm = ParseModrm(a, &disp);
reg = GetOpSize(a, opname, modrm, 1) << 3 | op;
EmitRexOpModrm(a, 0xC0, reg, modrm, disp, 1); // suboptimal
EmitByte(a, imm);
EmitExpr(a, imm, R_X86_64_8, EmitByte);
}
static noinline void OpBsu(struct As *a, struct Slice opname, int op) {
@ -2280,10 +2369,12 @@ static void OnTest(struct As *a, struct Slice s) {
if (IsPunct(a, a->i, '$')) {
++a->i;
imm = Parse(a);
ConsumeComma(a);
reg = OpF6(a, s, 0); // suboptimal
EmitImm(a, reg, imm);
} else {
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x84, reg, modrm, disp, 1);
}
@ -2294,18 +2385,21 @@ static void OnImul(struct As *a, struct Slice s) {
if (IsPunct(a, a->i, '$')) {
++a->i;
imm = Parse(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, 0x69, reg, modrm, disp, 0);
EmitImm(a, reg, imm);
} else {
modrm = ParseModrm(a, &disp);
if (IsPunct(a, a->i, ';')) {
reg = GetOpSize(a, s, modrm, 1) << 3 | 5;
EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1);
} else {
if (IsComma(a)) {
++a->i;
reg = GetRegisterReg(a);
EmitRexOpModrm(a, 0x0FAF, reg, modrm, disp, 0);
} else {
reg = GetOpSize(a, s, modrm, 1) << 3 | 5;
EmitRexOpModrm(a, 0xF6, reg, modrm, disp, 1);
}
}
}
@ -2313,6 +2407,7 @@ static void OnImul(struct As *a, struct Slice s) {
static void OpBit(struct As *a, int op) {
int reg, modrm, disp;
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, op, reg, modrm, disp, 0);
}
@ -2320,6 +2415,7 @@ static void OpBit(struct As *a, int op) {
static void OnXchg(struct As *a, struct Slice s) {
int reg, modrm, disp;
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x86, reg, modrm, disp, 1);
}
@ -2335,19 +2431,22 @@ static void OpShrld(struct As *a, struct Slice s, int op) {
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;
ConsumeComma(a);
skew = 1;
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0);
} else {
skew = 0;
ConsumePunct(a, '$');
imm = GetInt(a);
ConsumeComma(a);
reg = GetRegisterReg(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, 0x0F00 | op | skew, reg, modrm, disp, 0);
EmitByte(a, imm);
EmitExpr(a, imm, R_X86_64_8, EmitByte);
}
}
@ -2363,10 +2462,12 @@ static void OpSseMov(struct As *a, int opWsdVsd, int opVsdWsd) {
int reg, modrm, disp;
if (IsRegister(a, a->i)) {
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
EmitRexOpModrm(a, opWsdVsd, reg, modrm, disp, 0);
} else {
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, opVsdWsd, reg, modrm, disp, 0);
}
@ -2404,17 +2505,46 @@ static void OnMovapd(struct As *a, struct Slice s) {
OpSseMov(a, 0x0F29, 0x0F28);
}
static void OnMovdq(struct As *a, struct Slice s) {
int reg, modrm, boop, disp;
static void OpMovdq(struct As *a, bool is64) {
int reg, modrm, boop, disp, ugh;
EmitByte(a, 0x66); // todo mmx
if (IsRegister(a, a->i)) {
reg = GetRegisterReg(a);
ConsumeComma(a);
modrm = ParseModrm(a, &disp);
boop = ((reg & 070) >> 3) == 4 ? 0x10 : 0;
if (!(modrm & ISREG)) {
if (((reg & 070) >> 3) == 4) {
if (is64) reg |= REXW << 8;
boop = 0x10;
} else {
boop = 0;
}
} else {
if (((reg & 070) >> 3) == 4) {
boop = 0x10;
} else {
boop = 0;
ugh = modrm & 7;
modrm &= ~7;
modrm |= reg & 7;
reg &= ~7;
reg |= ugh;
}
}
} else {
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
boop = ((reg & 070) >> 3) == 4 ? 0x10 : 0;
if (!(modrm & ISREG)) {
if (((reg & 070) >> 3) == 4) {
if (is64) reg |= REXW << 8;
boop = 0;
} else {
boop = 0x10;
}
} else {
boop = ((modrm & 070) >> 3) == 4 ? 0 : 0x10;
}
}
EmitRexOpModrm(a, 0x0F6E + boop, reg, modrm, disp, 0);
}
@ -2442,6 +2572,7 @@ static noinline void OpSseImpl(struct As *a, int op) {
op &= 0xffff;
}
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, op, reg, modrm, disp, 0);
}
@ -2454,6 +2585,7 @@ static noinline void OpSseIbImpl(struct As *a, int op) {
int imm;
ConsumePunct(a, '$');
imm = Parse(a);
ConsumeComma(a);
OpSse(a, op);
EmitExpr(a, imm, R_X86_64_8, EmitByte);
}
@ -2474,9 +2606,13 @@ static bool HasXmmOnLine(struct As *a) {
return false;
}
static void OnMovd(struct As *a, struct Slice s) {
OpMovdq(a, false);
}
static void OnMovq(struct As *a, struct Slice s) {
if (HasXmmOnLine(a)) {
OnMovdq(a, s);
OpMovdq(a, true);
} else {
OnMov(a, s);
}
@ -2502,7 +2638,7 @@ static void OnPop(struct As *a, struct Slice s) {
static void OnNop(struct As *a, struct Slice opname) {
int modrm, disp;
if (IsPunct(a, a->i, ';')) {
if (IsSemicolon(a)) {
EmitByte(a, 0x90);
} else {
modrm = ParseModrm(a, &disp);
@ -2523,6 +2659,7 @@ static void OnRet(struct As *a, struct Slice s) {
static noinline void OpCmovccImpl(struct As *a, int cc) {
int reg, modrm, disp;
modrm = ParseModrm(a, &disp);
ConsumeComma(a);
reg = GetRegisterReg(a);
EmitRexOpModrm(a, 0x0F40 | cc, reg, modrm, disp, 0);
}
@ -2604,7 +2741,7 @@ static noinline void OpFpu1(struct As *a, int op, int reg) {
static void OnFxch(struct As *a, struct Slice s) {
int rm;
rm = !IsPunct(a, a->i, ';') ? GetRegisterRm(a) : 1;
rm = !IsSemicolon(a) ? GetRegisterRm(a) : 1;
EmitByte(a, 0xD9);
EmitByte(a, 0310 | rm & 7);
}
@ -2618,10 +2755,18 @@ static void OnBswap(struct As *a, struct Slice s) {
}
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");
int rm;
if (IsSemicolon(a)) {
rm = 1;
} else {
rm = GetRegisterRm(a);
if (IsComma(a)) {
++a->i;
if (GetRegisterReg(a) & 7) {
Fail(a, "bad register");
}
}
}
EmitVarword(a, op | rm & 7);
}
@ -2733,7 +2878,7 @@ 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 OnFldt(struct As *a, struct Slice s) { OpFpu1(a, 0xDB, 5); }
static void OnFldz(struct As *a, struct Slice s) { EmitVarword(a, 0xd9ee); }
static void OnFmulp(struct As *a, struct Slice s) { EmitVarword(a, 0xdec9); }
static void OnFnstcw(struct As *a, struct Slice s) { OpFpu1(a, 0xD9, 7); }
@ -3231,7 +3376,7 @@ static const struct Directive8 {
{"movapd", OnMovapd}, //
{"movaps", OnMovaps}, //
{"movb", OnMov}, //
{"movd", OnMovdq}, //
{"movd", OnMovd}, //
{"movdqa", OnMovdqa}, //
{"movdqa", OnMovdqa}, //
{"movdqu", OnMovdqu}, //
@ -3594,7 +3739,7 @@ static void OnDirective(struct As *a) {
for (;;) {
s = GetSlice(a);
if (Prefix(a, s.p, s.n)) {
if (IsPunct(a, a->i, ';')) {
if (IsSemicolon(a)) {
return;
}
} else {
@ -3611,7 +3756,7 @@ static void OnDirective(struct As *a) {
static void Assemble(struct As *a) {
while (a->i < a->things.n) {
if (IsPunct(a, a->i, ';')) {
if (IsSemicolon(a)) {
++a->i;
continue;
}
@ -3908,14 +4053,3 @@ void Assembler(int argc, char *argv[]) {
/* malloc_stats(); */
FreeAssembler(a);
}
int main(int argc, char *argv[]) {
showcrashreports();
if (argc == 1) {
system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s");
system("objdump -xwd /tmp/o");
exit(0);
}
Assembler(argc, argv);
return 0;
}

30
third_party/chibicc/as.main.c vendored Normal file
View file

@ -0,0 +1,30 @@
/*-*- 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 "third_party/chibicc/chibicc.h"
int main(int argc, char *argv[]) {
showcrashreports();
if (argc == 1) {
system("o//third_party/chibicc/as.com -o /tmp/o /home/jart/trash/hog.s");
system("objdump -xwd /tmp/o");
exit(0);
}
Assembler(argc, argv);
return 0;
}

View file

@ -563,10 +563,15 @@ static void cc1(void) {
fclose(out);
}
static int CountArgv(char **argv) {
int n = 0;
while (*argv++) ++n;
return n;
}
static void assemble(char *input, char *output) {
char *as = getenv("AS");
if (!as || !*as) as = "as";
/* as = "o//third_party/chibicc/as.com"; */
StringArray arr = {};
strarray_push(&arr, as);
strarray_push(&arr, "-W");
@ -579,7 +584,11 @@ static void assemble(char *input, char *output) {
strarray_push(&arr, "-o");
strarray_push(&arr, output);
strarray_push(&arr, NULL);
if (1) {
Assembler(CountArgv(arr.data), arr.data);
} else {
handle_exit(run_subprocess(arr.data));
}
}
static void run_linker(StringArray *inputs, char *output) {

View file

@ -627,6 +627,12 @@ void output_javadown_asm(const char *, const char *);
void drop_dox(const StringArray *, const char *);
//
// as.c
//
void Assembler(int, char **);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_CHIBICC_CHIBICC_H_ */

View file

@ -95,7 +95,7 @@ o/$(MODE)/third_party/chibicc/chibicc.com.dbg: \
$(THIRD_PARTY_CHIBICC_A) \
$(APE) \
$(CRT) \
o/$(MODE)/third_party/chibicc/main.o \
o/$(MODE)/third_party/chibicc/chibicc.main.o \
$(THIRD_PARTY_CHIBICC_A).pkg
@$(APELINK)
o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
@ -103,7 +103,7 @@ o/$(MODE)/third_party/chibicc/chibicc2.com.dbg: \
$(THIRD_PARTY_CHIBICC2_A) \
$(APE) \
$(CRT) \
o/$(MODE)/third_party/chibicc/main.chibicc.o \
o/$(MODE)/third_party/chibicc/chibicc.main.chibicc.o \
$(THIRD_PARTY_CHIBICC2_A).pkg
@$(APELINK)