diff options
| author | Andrew Chambers <[email protected]> | 2021-10-10 16:58:01 +1300 |
|---|---|---|
| committer | Andrew Chambers <[email protected]> | 2021-10-10 16:58:01 +1300 |
| commit | d6f46d0e72aefed61e2887ce1d6f4601b48648fb (patch) | |
| tree | 15f34f0575baa8f202810b97b7f54eb9ae486164 | |
| parent | 54da6cf3b5a2ee14705857bb988af67378d4be2c (diff) | |
Add cmp and jcc.
| -rw-r--r-- | asm.peg | 42 | ||||
| -rw-r--r-- | main.c | 37 | ||||
| -rw-r--r-- | minias.h | 2 | ||||
| -rw-r--r-- | test/test.sh | 30 |
4 files changed, 86 insertions, 25 deletions
@@ -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; } @@ -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: @@ -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 "." } |
