diff options
| -rw-r--r-- | asm.peg | 31 | ||||
| -rw-r--r-- | main.c | 52 | ||||
| -rw-r--r-- | test/test.sh | 5 |
3 files changed, 47 insertions, 41 deletions
@@ -56,7 +56,7 @@ lea = | 'q'? ws s:m ws? ',' ws? d:r64 { $$ = INSTR(2, s, d); } ) { $$.instr.kind = ASM_LEA; } -imm-opargs = +imm-rm-opargs = 'b' ws s:imm8 ws? ',' ws? d:m { $$ = INSTR(0, s, d); } | 'w' ws s:imm16 ws? ',' ws? d:m { $$ = INSTR(1, s, d); } | 'l' ws s:imm32 ws? ',' ws? d:m { $$ = INSTR(2, s, d); } @@ -81,18 +81,18 @@ r-rm-opargs = | 'q'? ws s:r64 ws? ',' ws? d:r64 { $$ = INSTR(11, s, d); } mov = "mov" ( - args:imm-opargs { $$ = args; } + args:imm-rm-opargs { $$ = args; } | args:r-rm-opargs { args.instr.variant += 8; $$ = args; } ) { $$.instr.kind = ASM_MOV; } xchg = 'xchg' ( - 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); } - | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = INSTR(1, s, d); } - | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = INSTR(2, s, d); } - | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR(3, s, d); } - | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR(4, s, d); } - | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR(5, s, d); } + 'w'? ws s:ax ws? ',' ws? d:r16 { $$ = INSTR(0, s, d); } + | 'w'? ws s:r16 ws? ',' ws? d:ax { $$ = INSTR(1, s, d); } + | 'l'? ws s:eax ws? ',' ws? d:r32 { $$ = INSTR(2, s, d); } + | 'l'? ws s:r32 ws? ',' ws? d:eax { $$ = INSTR(3, s, d); } + | 'q'? ws s:rax ws? ',' ws? d:r64 { $$ = INSTR(4, s, d); } + | 'q'? ws s:r64 ws? ',' ws? d:rax { $$ = INSTR(5, s, d); } | args:r-rm-opargs { args.instr.variant += 6; $$ = args; } ) { $$.instr.kind = ASM_XCHG; } @@ -107,7 +107,7 @@ basic-op-args = | 'w'? ws s:imm16 ws? ',' ws? d:ax { $$ = INSTR(1, s, d); } | 'l'? ws s:imm32 ws? ',' ws? d:eax { $$ = INSTR(2, s, d); } | 'q'? ws s:imm32 ws? ',' ws? d:rax { $$ = INSTR(3, s, d); } - | args:imm-opargs { args.instr.variant += 4; $$ = args; } + | args:imm-rm-opargs { args.instr.variant += 4; $$ = args; } | args:r-rm-opargs { args.instr.variant += 12; $$ = args; } r64-or-rip = ( @@ -116,13 +116,12 @@ r64-or-rip = ( ) { $$ = r; } m = - '(' ws? r:r64-or-rip ws? ')' - { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = NULL, .reg = r.kind }; } - - # | <'-'?[0-9]+> ws? '(' ws? r:r64 ws? ')' - # { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = strtoll(yytext, NULL, 10), .l = NULL, .reg = r.kind }; } - # | i:ident ws? '(' ws? r:r64 ws? ')' - # { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = i.ident.name, .reg = r.kind }; } + '(' ws? r:r64-or-rip ws? ')' + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = NULL, .reg = r.kind }; } + | <'-'?[0-9]+> ws? '(' ws? r:r64-or-rip ws? ')' + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = strtoll(yytext, NULL, 10), .l = NULL, .reg = r.kind }; } + | i:ident ws? '(' ws? r:r64-or-rip ws? ')' + { $$.memarg = (Memarg){ .kind = ASM_MEMARG, .c = 0, .l = i.ident.name, .reg = r.kind }; } imm8 = i:imm { i.imm.nbytes = 1; $$ = i; } imm16 = i:imm { i.imm.nbytes = 2; $$ = i; } @@ -272,6 +272,11 @@ static uint8_t modregrm(uint8_t mod, uint8_t reg, uint8_t rm) { return (((mod & 3) << 6) | ((reg & 7) << 3) | (rm & 7)); } +/* Compose an sib byte - See intel manual. */ +static uint8_t sibbyte(uint8_t ss, uint8_t idx, uint8_t base) { + return (((ss & 3) << 6) | ((idx & 7) << 3) | (base & 7)); +} + /* Assemble op +rw | op + rd. */ static void assembleplusr(uint8_t opcode, AsmKind reg) { uint8_t bits = regbits(reg); @@ -331,37 +336,35 @@ static void assembleriprel(Memarg *memarg, uint8_t rexw, uint8_t opcode, /* Assemble a r <-> mem operation. */ static void assemblemem(Memarg *memarg, uint8_t rexw, uint8_t opcode, uint8_t reg, uint8_t opsz) { - int wantsib, wantdisp; - uint8_t rex, mod, rm, sib; + uint8_t rex, rm, sib; - wantsib = 0; - wantdisp = 0; rm = regbits(memarg->reg); - /* Matches '(%rsp/%esp...)'. */ - if ((rm & 7) == 4) - lfatal("addressing mode unrepresentable"); - if (memarg->c == 0 && memarg->l == NULL) { - if ((rm & 7) == 5) { /* Matches '(%rbp/%ebp...)'. */ - mod = 0x01; - wantsib = 1; - sib = 0; - } else { - mod = 0x00; - } - } else { - lfatal("TODO X"); - } - if (opsz == 2) sb(0x66); - rex = rexbyte(rexw, 0, 0, rm & (1 << 3)); + rex = rexbyte(rexw, reg & (1 << 3), 0, rm & (1 << 3)); if (rex != rexbyte(0, 0, 0, 0)) sb(rex); - sb2(opcode, modregrm(mod, reg, rm)); - if (wantsib) - sb(sib); - if (wantdisp) + + if (memarg->c == 0 && memarg->l == NULL) { + /* No offset cases, uses the smallest we can. */ + if ((rm & 7) == 4) { /* Matches '(%rsp/%esp...)'. */ + sb3(opcode, modregrm(0, reg, 4), sibbyte(0, 4, 4)); + } else if ((rm & 7) == 5) { /* Matches '(%rbp/%ebp...)'. */ + sb3(opcode, modregrm(1, reg, 5), 0); + } else { + sb2(opcode, modregrm(0, reg, rm)); + } + } else { + /* XXX choose smaller size if not label .*/ + if ((rm & 7) == 4) { /* Matches '(%rsp/%esp...)'. */ + sb3(opcode, modregrm(2, reg, 4), sibbyte(0, 4, 4)); + } else if ((rm & 7) == 5) { /* Matches '(%rbp/%ebp...)'. */ + sb2(opcode, modregrm(2, reg, 5)); + } else { + sb2(opcode, modregrm(2, reg, rm)); + } assemblevalue(memarg->l, memarg->c, 4); + } } /* Assemble op + imm -> r/m. */ @@ -447,7 +450,6 @@ static void assemblexchg(Instr *xchg) { assembleplusr(opcode, (xchg->variant % 2) ? xchg->src->kind : xchg->dst->kind); } else { - /* Uses a pattern in the variant table. */ uint8_t opsz = 1 << ((xchg->variant - 6) % 4); assemblerrm(xchg, opcode, opsz); } diff --git a/test/test.sh b/test/test.sh index 3fb4cc5..e8293a7 100644 --- a/test/test.sh +++ b/test/test.sh @@ -30,6 +30,11 @@ t () { echo -n "." } +t "movb \$127, (%rsp)" +t "movb \$127, (%rbp)" +t "movb \$127, 2147483647(%rsp)" +t "movb \$127, 2147483647(%rbp)" + for r in a b do t "xchg %${r}l, %${r}l" |
