aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Chambers <[email protected]>2021-10-10 16:58:01 +1300
committerAndrew Chambers <[email protected]>2021-10-10 16:58:01 +1300
commitd6f46d0e72aefed61e2887ce1d6f4601b48648fb (patch)
tree15f34f0575baa8f202810b97b7f54eb9ae486164
parent54da6cf3b5a2ee14705857bb988af67378d4be2c (diff)
Add cmp and jcc.
-rw-r--r--asm.peg42
-rw-r--r--main.c37
-rw-r--r--minias.h2
-rw-r--r--test/test.sh30
4 files changed, 86 insertions, 25 deletions
diff --git a/asm.peg b/asm.peg
index 99a574b..6ff6b20 100644
--- a/asm.peg
+++ b/asm.peg
@@ -58,6 +58,7 @@ instr =
| i:jmp { $$ = i; }
| i:add { $$ = i; }
| i:and { $$ = i; }
+ | i:cmp { $$ = i; }
| i:div { $$ = i; }
| i:idiv { $$ = i; }
| i:lea { $$ = i; }
@@ -89,9 +90,41 @@ call =
"call" 'q'? ws t:ident
{ $$.call = (Call){ .kind = ASM_CALL, .target=t.charptr } ; }
-jmp =
- "jmp" ws t:ident
- { $$.jmp = (Jmp){ .kind = ASM_JMP, .target=t.charptr } ; }
+jmp = 'j' v:jmp-variant ws t:ident
+ { $$.jmp = (Jmp) {.kind = ASM_JMP, .variant=v.i64, .target=t.charptr}; }
+jmp-variant =
+ "mp" { $$.i64 = 0; }
+ | "a" { $$.i64 = 1; }
+ | "ae" { $$.i64 = 2; }
+ | "b" { $$.i64 = 3; }
+ | "be" { $$.i64 = 4; }
+ | "c" { $$.i64 = 5; }
+ | "e" { $$.i64 = 6; }
+ | "z" { $$.i64 = 7; }
+ | "g" { $$.i64 = 8; }
+ | "ge" { $$.i64 = 9; }
+ | "l" { $$.i64 = 10; }
+ | "le" { $$.i64 = 11; }
+ | "na" { $$.i64 = 12; }
+ | "nae" { $$.i64 = 13; }
+ | "nb" { $$.i64 = 14; }
+ | "nbe" { $$.i64 = 15; }
+ | "nc" { $$.i64 = 16; }
+ | "ne" { $$.i64 = 17; }
+ | "ng" { $$.i64 = 18; }
+ | "nge" { $$.i64 = 19; }
+ | "nl" { $$.i64 = 20; }
+ | "nle" { $$.i64 = 21; }
+ | "no" { $$.i64 = 22; }
+ | "np" { $$.i64 = 23; }
+ | "ns" { $$.i64 = 24; }
+ | "nz" { $$.i64 = 25; }
+ | "o" { $$.i64 = 26; }
+ | "p" { $$.i64 = 27; }
+ | "pe" { $$.i64 = 28; }
+ | "po" { $$.i64 = 29; }
+ | "s" { $$.i64 = 30; }
+ | "z" { $$.i64 = 31; }
lea =
"lea" (
@@ -181,7 +214,8 @@ xchg =
| args:r-rm-opargs { args.instr.variant += 6; $$ = args; }
) { $$.instr.kind = ASM_XCHG; }
-add = "add" a:basic-op-args { a.instr.kind = ASM_ADD; $$ = a; }
+add = "cmp" a:basic-op-args { a.instr.kind = ASM_CMP; $$ = a; }
+cmp = "add" a:basic-op-args { a.instr.kind = ASM_ADD; $$ = a; }
and = "and" a:basic-op-args { a.instr.kind = ASM_AND; $$ = a; }
or = "or" a:basic-op-args { a.instr.kind = ASM_OR; $$ = a; }
sub = "sub" a:basic-op-args { a.instr.kind = ASM_SUB; $$ = a; }
diff --git a/main.c b/main.c
index 4fec4fc..8c08f9c 100644
--- a/main.c
+++ b/main.c
@@ -673,8 +673,16 @@ static void assemble(void) {
Symbol *sym;
Relocation *reloc;
- sb(0xe9);
- assemblereloc(v->call.target, -4, 4, R_X86_64_PC32);
+ static uint8_t variant2op[32] = {
+ 0xe9, 0x87, 0x83, 0x82, 0x86, 0x82, 0x84, 0x84, 0x8f, 0x8d, 0x8c,
+ 0x8e, 0x86, 0x82, 0x83, 0x87, 0x83, 0x85, 0x8e, 0x8c, 0x8d, 0x8f,
+ 0x81, 0x8b, 0x89, 0x85, 0x80, 0x8a, 0x8a, 0x8b, 0x88, 0x84,
+ };
+ if (v->jmp.variant)
+ sb(0x0f);
+ sb(variant2op[v->jmp.variant]);
+
+ assemblereloc(v->jmp.target, -4, 4, R_X86_64_PC32);
break;
}
case ASM_PUSH:
@@ -726,6 +734,15 @@ static void assemble(void) {
assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x04);
break;
}
+ case ASM_CMP: {
+ static uint8_t variant2op[24] = {
+ 0x3c, 0x3d, 0x3d, 0x3d, 0x80, 0x81, 0x81, 0x81,
+ 0x80, 0x81, 0x81, 0x81, 0x3a, 0x3b, 0x3b, 0x3b,
+ 0x38, 0x39, 0x39, 0x39, 0x38, 0x39, 0x39, 0x39,
+ };
+ assemblebasicop(&v->instr, variant2op[v->instr.variant], 0x07);
+ break;
+ }
case ASM_DIV:
assembledivmul(&v->instr, 0x06);
break;
@@ -860,7 +877,7 @@ static void fillsymtab(void) {
static void resolvereloc(Relocation *reloc) {
Symbol *sym;
uint8_t *rdata;
- int32_t addend, value;
+ int64_t addend, value;
sym = reloc->sym;
@@ -869,14 +886,22 @@ static void resolvereloc(Relocation *reloc) {
rdata = &reloc->section->data[reloc->offset];
addend = (int32_t)rdata[0] | (int32_t)(rdata[1] << 8) |
(int32_t)(rdata[2] << 16) | (int32_t)(rdata[3] << 24);
- value = sym->offset - (int32_t)reloc->offset + addend;
+ value = sym->offset - reloc->offset + addend;
rdata[0] = ((uint32_t)value & 0xff);
rdata[1] = ((uint32_t)value & 0xff00) >> 8;
rdata[2] = ((uint32_t)value & 0xff0000) >> 16;
rdata[3] = ((uint32_t)value & 0xff000000) >> 24;
break;
- case R_X86_64_PC32:
- fatal("TODO local R_X86_64_PC32");
+ }
+ case R_X86_64_PC32: {
+ rdata = &reloc->section->data[reloc->offset];
+ addend = (int32_t)rdata[0] | (int32_t)(rdata[1] << 8) |
+ (int32_t)(rdata[2] << 16) | (int32_t)(rdata[3] << 24);
+ value = sym->offset - reloc->offset + addend;
+ rdata[0] = ((uint32_t)value & 0xff);
+ rdata[1] = ((uint32_t)value & 0xff00) >> 8;
+ rdata[2] = ((uint32_t)value & 0xff0000) >> 16;
+ rdata[3] = ((uint32_t)value & 0xff000000) >> 24;
break;
}
default:
diff --git a/minias.h b/minias.h
index 9becc49..ac861da 100644
--- a/minias.h
+++ b/minias.h
@@ -64,6 +64,7 @@ typedef enum {
ASM_LEAVE,
ASM_ADD,
ASM_AND,
+ ASM_CMP,
ASM_DIV,
ASM_IDIV,
ASM_LEA,
@@ -215,6 +216,7 @@ typedef struct {
typedef struct {
AsmKind kind;
+ uint8_t variant;
const char *target;
} Jmp;
diff --git a/test/test.sh b/test/test.sh
index ecc4624..6126d1c 100644
--- a/test/test.sh
+++ b/test/test.sh
@@ -32,18 +32,18 @@ t () {
for op in sal sar shl shr
do
-t "${op} \$3, %rax"
-t "${op} %cl, %rax"
-t "${op} \$3, %eax"
-t "${op} %cl, %eax"
-t "${op} \$3, %ax"
-t "${op} %cl, %ax"
-t "${op}w \$3, (%rax)"
-t "${op}w %cl, (%rax)"
-t "${op}l \$3, (%rax)"
-t "${op}l %cl, (%rax)"
-t "${op}q \$3, (%rax)"
-t "${op}q %cl, (%rax)"
+ t "${op} \$3, %rax"
+ t "${op} %cl, %rax"
+ t "${op} \$3, %eax"
+ t "${op} %cl, %eax"
+ t "${op} \$3, %ax"
+ t "${op} %cl, %ax"
+ t "${op}w \$3, (%rax)"
+ t "${op}w %cl, (%rax)"
+ t "${op}l \$3, (%rax)"
+ t "${op}l %cl, (%rax)"
+ t "${op}q \$3, (%rax)"
+ t "${op}q %cl, (%rax)"
done
t "div %rax"
@@ -114,7 +114,7 @@ for r in a b
t "leaw (%r${r}x), %${r}x"
done
-for op in mov add and or sub xor
+for op in mov add and cmp or sub xor
do
# rip relative
t "${op}b \$127, (%rip)"
@@ -170,8 +170,8 @@ t () {
clang "$tmpo" -o "$tmpb"
if !"$tmpb" 1>&2 2>/dev/null
then
- echo "$t failed"
- exit 1
+ echo "$t failed"
+ exit 1
fi
echo -n "."
}