aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asm.peg31
-rw-r--r--main.c52
-rw-r--r--test/test.sh5
3 files changed, 47 insertions, 41 deletions
diff --git a/asm.peg b/asm.peg
index 661fefb..256603d 100644
--- a/asm.peg
+++ b/asm.peg
@@ -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; }
diff --git a/main.c b/main.c
index 3337bcc..191d1d5 100644
--- a/main.c
+++ b/main.c
@@ -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"