commit ffe76c7c9ca25412638fc552cf6e5c68be1d61ce
parent dd5fa13571a7ac1f16c88b3590502e1ed4e8b359
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Sat, 9 Sep 2017 06:39:29 +0200
[as] Add support for data definitions
Add DB, DW, DD and DQ
Diffstat:
12 files changed, 193 insertions(+), 53 deletions(-)
diff --git a/as/as.h b/as/as.h
@@ -5,16 +5,23 @@ enum secflags {
SFILE,
};
+enum args {
+ AIMM = 1,
+ AMAX,
+ AREP = 1 << 7,
+};
+
+enum endianess {
+ BIG_ENDIAN = -1,
+ LITTLE_ENDIAN = 1
+};
+
typedef struct ins Ins;
typedef struct op Op;
typedef struct arg Arg;
typedef void Format(Op *, Arg *);
typedef struct section Section;
-enum {
- BITS16,
-};
-
struct ins {
int begin, end;
char *str;
@@ -25,11 +32,11 @@ struct op {
int size;
void (*format)(Op *, Arg *);
char *bytes;
- char *args;
+ unsigned char *args;
};
struct arg {
- int type;
+ unsigned char type;
TUINT val;
};
@@ -48,6 +55,7 @@ extern void isections(void);
extern void writeout(char *name);
extern void emit(Section *sec, char *bytes, int nbytes);
extern Section *section(char *name);
+extern void incpc(int siz);
extern Section *cursec;
extern int nr_ins;
@@ -55,3 +63,4 @@ extern Ins instab[];
extern Op optab[];
extern int pass;
extern TUINT maxaddr;
+extern int endian;
diff --git a/as/common.dat b/as/common.dat
@@ -0,0 +1,6 @@
+# Tab 16, tabs 16, :set ts=16
+# op args size bytes format
+DB imm8* 0 none defb
+DW imm16* 0 none defw
+DD imm32* 0 none defd
+DQ imm64* 0 none defq
diff --git a/as/emit.c b/as/emit.c
@@ -43,13 +43,6 @@ isect(Section *sec)
}
Section *
-addsect(char *name, TUINT base, int flags)
-{
- Section *sec;
-
-}
-
-Section *
section(char *name)
{
Section *sec;
@@ -78,15 +71,11 @@ isections(void)
}
void
-emit(Section *sec, char *bytes, int nbytes)
+emit(Section *sec, char *bytes, int n)
{
- TUINT addr;
-
- if (!sec->mem)
- return;
-
- for (addr = sec->pc - sec->base; nbytes--; addr++)
- sec->mem[addr] = *bytes++;
+ if (sec->mem)
+ memcpy(&sec->mem[sec->pc - sec->base], bytes, n);
+ incpc(n);
}
void
diff --git a/as/ins.c b/as/ins.c
@@ -8,3 +8,49 @@ direct(Op *op, Arg *args)
{
emit(cursec, op->bytes, op->size);
}
+
+char *
+pack(TUINT v, int n, int inc)
+{
+ static char buf[sizeof(TUINT)];
+ int idx;
+
+ idx = (inc < 0) ? n-1 : 0;
+ while (n--) {
+ buf[idx] = v;
+ idx += inc;
+ v >>= 8;
+ }
+ return buf;
+}
+
+void
+def(Arg *args, int siz)
+{
+ for ( ; args->type; ++args)
+ emit(cursec, pack(args->val, siz, endian), siz);
+}
+
+void
+defb(Op *op, Arg *args)
+{
+ def(args, 1);
+}
+
+void
+defw(Op *op, Arg *args)
+{
+ def(args, 2);
+}
+
+void
+defd(Op *op, Arg *args)
+{
+ def(args, 4);
+}
+
+void
+defq(Op *op, Arg *args)
+{
+ def(args, 8);
+}
diff --git a/as/ins.h b/as/ins.h
@@ -1,2 +1,2 @@
-Format direct;
+Format direct, defb, defw, defd, defq;
diff --git a/as/main.c b/as/main.c
@@ -1,4 +1,5 @@
+#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -8,6 +9,8 @@
#include "as.h"
#define MAXLINE 100
+#define NARGS 20
+
int nerrors;
void
@@ -28,7 +31,6 @@ cmp(const void *f1, const void *f2)
{
const Ins *ins = f2;
-
return strcmp(f1, ins->str);
}
@@ -38,10 +40,81 @@ match(Op *op, Arg *args)
return 1;
}
+Arg
+number(char *s, int base)
+{
+ Arg arg;
+ TUINT n;
+
+ /* TODO: Check overflow here */
+ arg.type = AIMM;
+ for (n = 0; *s; n += *s++ - '0')
+ n *= base;
+ arg.val = n;
+
+ return arg;
+}
+
Arg *
-getargs(char *text)
+getargs(char *s)
{
- return NULL;
+ char *t;
+ int ch, len;
+ Arg *ap;
+ static Arg args[NARGS];
+
+ for (ap = args; ; ++ap) {
+ while (isspace(*s))
+ ++s;
+ if (*s == '\0')
+ break;
+ if (ap == &args[NARGS-1])
+ die("too many arguments in one instruction");
+
+ for (t = s; *s && *s != ','; s++)
+ /* nothing */;
+ len = t - s;
+ if (len == 0)
+ goto wrong_operand;
+
+ if (*s)
+ *s++ = '\0';
+
+ ch = *t;
+ if (isdigit(ch)) {
+ *ap = number(t, (s[len-1] == 'H') ? 16 : 10);
+ continue;
+ }
+wrong_operand:
+ error("wrong operand '%s'", t);
+ }
+ ap->type = 0;
+
+ return args;
+}
+
+void
+incpc(int siz)
+{
+ TUINT pc, curpc;
+ pc = cursec->pc;
+ curpc = cursec->curpc;
+
+ cursec->curpc += siz;
+ cursec->pc += siz;
+
+ if (pass == 2)
+ return;
+
+ if (cursec->pc > cursec->max)
+ cursec->max = cursec->pc;
+
+ if (pc > cursec->pc ||
+ curpc > cursec->curpc ||
+ cursec->curpc > maxaddr ||
+ cursec->pc > maxaddr) {
+ die("address overflow");
+ }
}
void
@@ -50,7 +123,6 @@ as(char *text, char *xargs)
Ins *ins;
Op *op, *lim;
Arg *args;
- TUINT pc, curpc;
ins = bsearch(text, instab, nr_ins, sizeof(Ins), cmp);
@@ -70,25 +142,6 @@ as(char *text, char *xargs)
return;
}
(*op->format)(op, args);
-
- pc = cursec->pc;
- curpc = cursec->curpc;
-
- cursec->curpc += op->size;
- cursec->pc += op->size;
-
- if (pass == 2)
- return;
-
- if (cursec->pc > cursec->max)
- cursec->max = cursec->pc;
-
- if (pc > cursec->pc ||
- curpc > cursec->curpc ||
- cursec->curpc > maxaddr ||
- cursec->pc > maxaddr) {
- die("address overflow");
- }
}
int
diff --git a/as/target/amd64/ins.c b/as/target/amd64/ins.c
@@ -4,3 +4,4 @@
#include "ins.h"
TUINT maxaddr = 0xFFFFFFFFFFFFFFFF;
+int endian = LITTLE_ENDIAN;
diff --git a/as/target/amd64/target.mk b/as/target/amd64/target.mk
@@ -1,8 +1,10 @@
-AMD64_TBL = target/x86/i386.dat target/x86/amd64.dat
+AMD64_TBL = common.dat \
+ target/x86/i386.dat \
+ target/x86/amd64.dat
target/amd64/instbl.o: target/amd64/ins.h
-target/amd64/instbl.c: target/x86/gen.awk $(AMD64_SHDEP)
+target/amd64/instbl.c: target/x86/gen.awk $(AMD64_TBL)
set -e ;\
rm -f $@;\
trap "rm -f $$$$.c" 0 2 3; \
diff --git a/as/target/i386/ins.c b/as/target/i386/ins.c
@@ -4,3 +4,4 @@
#include "ins.h"
TUINT maxaddr = 0xFFFFFFFF;
+int endian = LITTLE_ENDIAN;
diff --git a/as/target/i386/target.mk b/as/target/i386/target.mk
@@ -1,12 +1,15 @@
+I386_TBL = common.dat \
+ target/x86/i386.dat
target/i386/ins.o: target/i386/ins.h
target/i386/instbl.o: target/i386/ins.h
-target/i386/instbl.c: target/x86/gen.awk target/x86/i386.dat
+target/i386/instbl.c: target/x86/gen.awk $(I386_TBL)
set -e ;\
rm -f $@;\
trap "rm -f $$$$.c" 0 2 3; \
- awk -f target/x86/gen.awk < target/x86/i386.dat > $$$$.c && mv $$$$.c $@
+ cat $(I386_TBL) | \
+ awk -f target/x86/gen.awk > $$$$.c && mv $$$$.c $@
OBJ-i386 = $(OBJ) \
target/i386/instbl.o \
diff --git a/as/target/x86/args.h b/as/target/x86/args.h
@@ -0,0 +1,7 @@
+
+enum args_x86 {
+ AIMM8 = AMAX,
+ AIMM16,
+ AIMM32,
+ AIMM64,
+};
diff --git a/as/target/x86/gen.awk b/as/target/x86/gen.awk
@@ -4,6 +4,7 @@ BEGIN {
printf "#include \"../../../inc/scc.h\"\n"\
"#include \"../../as.h\"\n"\
"#include \"../../ins.h\"\n"\
+ "#include \"../x86/args.h\"\n"\
"#include \"ins.h\"\n\n"
nop = 0; nvar = 0
}
@@ -17,7 +18,7 @@ BEGIN {
opcount[$1]++
opargs[nvar] = $2
opsize[nvar] = $3
- opbytes[nvar] = $4
+ opbytes[nvar] = ($4 == "none") ? "" : $4
opformat[nvar++] = $5
}
END {
@@ -39,14 +40,36 @@ END {
"\t\t.bytes = (char []) {%s},\n"\
"\t\t.size = %d,\n"\
"\t\t.format = %s,\n"\
- "\t\t.args = \"%s\"\n"\
+ "\t\t.args = (char []) {%s}\n"\
"\t},\n",
opbytes[i], opsize[i], opformat[i], str2args(opargs[i])
}
print "};"
}
-function str2args(s)
+function str2args(s, args, i, out)
{
- return ""
+ split(s, args, /,/)
+ for (i in args) {
+ if (args[i] == "none")
+ break
+ else if (args[i] ~ /imm8/)
+ out = "AIMM8"
+ else if (args[i] ~ /imm16/)
+ out = "AIMM16"
+ else if (args[i] ~ /imm32/)
+ out = "AIMM32"
+ else if (args[i] ~ /imm64/)
+ out = "AIMM64"
+ else {
+ print "wrong arg", args[i]
+ exit 1
+ }
+ if (args[i] ~ /\*$/)
+ return out "|AREP"
+ out = out ","
+ }
+ out = out "0"
+
+ return out
}