6 #define TMP_ADDR 0x0001
10 #define LOC_SYM 0x0800
11 #define LOC_LOCAL 0x1000
12 #define LOC_MASK 0xff00
49 #define R_BYTEMASK (1 << R_RAX | 1 << R_RDX | 1 << R_RCX)
50 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? 8 : (t)->bt)
51 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
52 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
53 (t)->addr : reg_get(~(1 << r)))
54 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
55 (1 << (t)->addr) & R_BYTEMASK ? \
56 (t)->addr : reg_get(R_BYTEMASK))
57 #define BT_TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
59 static char buf
[SECSIZE
];
62 static long spsub_addr
;
74 static struct tmp
*regs
[NREGS
];
75 static int tmpregs
[] = {R_RAX
, R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
77 #define MAXRET (1 << 8)
79 static long ret
[MAXRET
];
85 static void putint(char *s
, long n
, int l
)
93 static void os(char *s
, int n
)
99 static void oi(long n
, int l
)
107 static long codeaddr(void)
112 static void o_op(int *op
, int nop
, int r1
, int r2
, unsigned bt
)
120 if (rex
|| (bt
& BT_SZMASK
) == 8)
122 if ((bt
& BT_SZMASK
) == 2)
124 if ((bt
& BT_SZMASK
) == 1)
126 for (i
= 0; i
< nop
; i
++)
130 static void memop(int *op
, int nop
, int src
, int base
, int off
, unsigned bt
)
132 int dis
= off
== (char) off
? 1 : 4;
133 int mod
= dis
== 4 ? 2 : 1;
134 o_op(op
, nop
, src
, base
, bt
);
137 oi((mod
<< 6) | ((src
& 0x07) << 3) | (base
& 0x07), 1);
142 static void memop1(int op
, int src
, int base
, int off
, unsigned bt
)
144 memop(&op
, 1, src
, base
, off
, bt
);
147 static void regop(int op
, int src
, int dst
, unsigned bt
)
149 o_op(&op
, 1, src
, dst
, bt
);
150 oi((3 << 6) | (src
<< 3) | (dst
& 0x07), 1);
153 static long sp_push(int size
)
161 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
163 static void tmp_mem(struct tmp
*tmp
)
166 if (!(tmp
->flags
& LOC_REG
))
170 tmp
->addr
= sp_push(8);
171 memop1(MOV_R2X
, src
, R_RBP
, -tmp
->addr
, BT_TMPBT(TMP_BT(tmp
)));
173 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_MEM
);
176 static void mov_m2r(int dst
, int base
, int off
, int bt
)
178 int movxx
[2] = {0x0f};
181 movxx
[1] = bt
& BT_SIGNED
? 0xbe : 0xb6;
183 movxx
[1] = bt
& BT_SIGNED
? 0xbf : 0xb7;
184 memop(movxx
, 2, dst
, base
, off
, BT_SIGNED
? 8 : 4);
187 memop1(MOV_M2R
, dst
, base
, off
, bt
);
190 static void tmp_reg(struct tmp
*tmp
, unsigned dst
, int deref
)
192 if (!(tmp
->flags
& TMP_ADDR
))
195 tmp
->flags
&= ~TMP_ADDR
;
196 if (tmp
->flags
& LOC_NUM
) {
197 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
198 oi(tmp
->addr
, BT_SZ(tmp
->bt
));
201 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
203 if (tmp
->flags
& LOC_SYM
) {
204 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
205 out_rela(tmp
->addr
, codeaddr(), 0);
209 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
211 if (tmp
->flags
& LOC_REG
) {
213 mov_m2r(dst
, tmp
->addr
, 0, tmp
->bt
);
215 if (dst
== tmp
->addr
)
217 regop(MOV_R2X
, tmp
->addr
, dst
, BT_TMPBT(TMP_BT(tmp
)));
219 regs
[tmp
->addr
] = NULL
;
224 if (tmp
->flags
& LOC_LOCAL
) {
226 mov_m2r(dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
228 memop1(LEA_M2R
, dst
, R_RBP
, -tmp
->addr
, 8);
230 if (tmp
->flags
& LOC_MEM
) {
231 mov_m2r(dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
233 mov_m2r(dst
, dst
, 0, TMP_BT(tmp
));
237 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
240 static void reg_free(int reg
)
245 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
246 if (!regs
[tmpregs
[i
]]) {
247 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
253 static void reg_for(int reg
, struct tmp
*t
)
255 if (regs
[reg
] && regs
[reg
] != t
)
259 static unsigned tmp_pop(int deref
, int reg
)
261 struct tmp
*t
= &tmp
[--ntmp
];
263 tmp_reg(t
, reg
, deref
);
268 static void tmp_push_reg(unsigned bt
, unsigned reg
)
270 struct tmp
*t
= &tmp
[ntmp
++];
277 void o_local(long addr
, unsigned bt
)
279 struct tmp
*t
= &tmp
[ntmp
++];
282 t
->flags
= LOC_LOCAL
| TMP_ADDR
;
285 void o_num(long num
, unsigned bt
)
287 struct tmp
*t
= &tmp
[ntmp
++];
293 void o_symaddr(long addr
, unsigned bt
)
295 struct tmp
*t
= &tmp
[ntmp
++];
298 t
->flags
= LOC_SYM
| TMP_ADDR
;
301 void o_tmpdrop(int n
)
304 if (n
== -1 || n
> ntmp
)
307 for (i
= ntmp
; i
< ntmp
+ n
; i
++)
308 if (tmp
[i
].flags
& LOC_REG
)
309 regs
[tmp
[i
].addr
] = NULL
;
317 #define FORK_REG R_RAX
321 struct tmp
*t
= &tmp
[ntmp
- 1];
322 reg_for(FORK_REG
, t
);
323 tmp_reg(t
, FORK_REG
, 0);
329 struct tmp
*t
= &tmp
[ntmp
- 1];
330 reg_for(FORK_REG
, t
);
331 tmp_reg(t
, FORK_REG
, 0);
336 struct tmp
*t1
= &tmp
[ntmp
- 1];
337 struct tmp
*t2
= &tmp
[ntmp
- 2];
339 memcpy(&t
, t1
, sizeof(t
));
340 memcpy(t1
, t2
, sizeof(t
));
341 memcpy(t2
, &t
, sizeof(t
));
344 static int reg_get(int mask
)
347 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
348 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]])
350 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
351 if ((1 << tmpregs
[i
]) & mask
) {
352 reg_free(tmpregs
[i
]);
360 struct tmp
*t1
= &tmp
[ntmp
- 1];
361 struct tmp
*t2
= &tmp
[ntmp
++];
362 if (!(t1
->flags
& (LOC_REG
| LOC_MEM
))) {
363 memcpy(t2
, t1
, sizeof(*t2
));
366 memcpy(t2
, t1
, sizeof(*t1
));
367 if (t1
->flags
& LOC_MEM
) {
368 tmp_reg(t2
, reg_get(~0), 0);
369 } else if (t1
->flags
& LOC_REG
) {
370 t2
->addr
= reg_get(~t1
->addr
);
371 regop(MOV_R2X
, t1
->addr
, t2
->addr
, BT_TMPBT(TMP_BT(tmp
)));
373 t2
->flags
= t1
->flags
;
376 long o_func_beg(char *name
)
378 long addr
= out_func_beg(name
);
380 os("\x55", 1); /* push %rbp */
381 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
388 memset(regs
, 0, sizeof(regs
));
389 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
390 spsub_addr
= codeaddr();
395 void o_deref(unsigned bt
)
397 struct tmp
*t
= &tmp
[ntmp
- 1];
398 if (t
->flags
& TMP_ADDR
)
399 tmp_reg(t
, TMP_REG(t
), 1);
401 t
->flags
|= TMP_ADDR
;
406 struct tmp
*t
= &tmp
[ntmp
- 1];
407 tmp_reg(t
, TMP_REG(t
), 1);
410 static void shx(int uop
, int sop
)
412 struct tmp
*t
= &tmp
[ntmp
- 2];
414 unsigned reg
= TMP_REG2(t
, R_RCX
);
416 bt
= tmp_pop(1, reg
);
417 regop(SHX_REG
, bt
& BT_SIGNED
? sop
: uop
, reg
, BT_TMPBT(bt
));
418 tmp_push_reg(bt
, reg
);
431 static unsigned bt_op(unsigned bt1
, unsigned bt2
)
433 unsigned s1
= BT_SZ(bt1
);
434 unsigned s2
= BT_SZ(bt2
);
435 return (bt1
| bt2
) & BT_SIGNED
| (s1
> s2
? s1
: s2
);
438 static int mulop(int uop
, int sop
, int reg
)
440 struct tmp
*t1
= &tmp
[ntmp
- 1];
441 struct tmp
*t2
= &tmp
[ntmp
- 2];
442 int bt1
= TMP_BT(t1
);
443 int bt2
= TMP_BT(t2
);
444 if (t1
->flags
& LOC_REG
&& t1
->addr
!= R_RAX
&& t1
->addr
!= R_RDX
)
449 tmp_reg(t2
, R_RAX
, 1);
453 regop(MUL_A2X
, bt2
& BT_SIGNED
? sop
: uop
, reg
, BT_TMPBT(bt2
));
454 return bt_op(bt1
, bt2
);
459 int bt
= mulop(4, 5, R_RDX
);
460 tmp_push_reg(bt
, R_RAX
);
465 int bt
= mulop(6, 7, R_RCX
);
466 tmp_push_reg(bt
, R_RAX
);
471 int bt
= mulop(6, 7, R_RCX
);
472 tmp_push_reg(bt
, R_RDX
);
477 tmp
[ntmp
- 1].flags
&= ~TMP_ADDR
;
478 tmp
[ntmp
- 1].bt
= 8;
481 void o_ret(unsigned bt
)
486 os("\x31\xc0", 2); /* xor %eax, %eax */
487 ret
[nret
++] = o_jmp(0);
490 static int binop(int op
, int *reg
)
492 struct tmp
*t1
= &tmp
[ntmp
- 1];
493 struct tmp
*t2
= &tmp
[ntmp
- 2];
495 unsigned bt1
, bt2
, bt
;
497 *reg
= TMP_REG2(t2
, r1
);
498 bt1
= tmp_pop(1, r1
);
499 bt2
= tmp_pop(1, *reg
);
500 bt
= bt_op(bt1
, bt2
);
501 regop(op
, *reg
, r1
, BT_TMPBT(bt
));
508 int bt
= binop(ADD_R2X
, ®
);
509 tmp_push_reg(bt
, reg
);
515 int bt
= binop(XOR_R2X
, ®
);
516 tmp_push_reg(bt
, reg
);
522 int bt
= binop(AND_R2X
, ®
);
523 tmp_push_reg(bt
, reg
);
529 int bt
= binop(OR_R2X
, ®
);
530 tmp_push_reg(bt
, reg
);
536 int bt
= binop(SUB_R2X
, ®
);
537 tmp_push_reg(bt
, reg
);
540 static void o_cmp(int uop
, int sop
)
542 char set
[] = "\x0f\x00\xc0";
544 int bt
= binop(CMP_R2X
, ®
);
545 set
[1] = bt
& BT_SIGNED
? sop
: uop
;
547 cmp_setl
= codeaddr();
548 os(set
, 3); /* setl %al */
549 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
550 tmp_push_reg(4 | BT_SIGNED
, R_RAX
);
551 cmp_last
= codeaddr();
586 if (cmp_last
== codeaddr()) {
587 buf
[cmp_setl
+ 1] ^= 0x10;
589 o_num(0, 4 | BT_SIGNED
);
596 struct tmp
*t
= &tmp
[ntmp
- 1];
597 int reg
= TMP_REG(t
);
599 regop(NEG_REG
, 3, reg
, BT_TMPBT(t
->bt
));
600 tmp_push_reg(t
->bt
, reg
);
605 struct tmp
*t
= &tmp
[ntmp
- 1];
606 int reg
= TMP_REG(t
);
608 regop(NOT_REG
, 2, reg
, BT_TMPBT(t
->bt
));
609 tmp_push_reg(t
->bt
, reg
);
612 void o_func_end(void)
615 for (i
= 0; i
< nret
; i
++)
617 os("\xc9\xc3", 2); /* leave; ret; */
618 putint(buf
+ spsub_addr
, (maxsp
+ 7) & ~0x07, 4);
619 out_func_end(buf
, cur
- buf
);
622 long o_mklocal(int size
)
624 return sp_push((size
+ 7) & ~0x07);
627 static int arg_regs
[] = {R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
629 long o_arg(int i
, unsigned bt
)
631 long addr
= o_mklocal(BT_SZ(bt
));
632 memop1(MOV_R2X
, arg_regs
[i
], R_RBP
, -addr
, bt
);
636 void o_assign(unsigned bt
)
638 struct tmp
*t1
= &tmp
[ntmp
- 1];
639 struct tmp
*t2
= &tmp
[ntmp
- 2];
640 int r1
= BT_SZ(bt
) > 1 ? TMP_REG(t1
) : TMP_BYTEREG(t1
);
644 if (t2
->flags
& LOC_LOCAL
) {
649 reg
= TMP_REG2(t2
, r1
);
653 memop1(MOV_R2X
, r1
, reg
, off
, bt
);
654 tmp_push_reg(bt
, r1
);
662 static long jx(int x
, long addr
)
666 os(op
, 2); /* jx $addr */
667 oi(addr
- codeaddr() - 4, 4);
668 return codeaddr() - 4;
671 static long jxtest(int x
, long addr
)
673 int bt
= tmp_pop(1, R_RAX
);
674 regop(TEST_R2R
, R_RAX
, R_RAX
, BT_TMPBT(bt
));
678 static long jxcmp(long addr
, int inv
)
681 if (codeaddr() != cmp_last
)
684 cur
= buf
+ cmp_setl
;
685 x
= (unsigned char) buf
[cmp_setl
+ 1];
686 return jx((inv
? x
: x
^ 0x01) & ~0x10, addr
);
691 long ret
= jxcmp(addr
, 0);
692 return ret
!= -1 ? ret
: jxtest(0x84, addr
);
695 long o_jnz(long addr
)
697 long ret
= jxcmp(addr
, 1);
698 return ret
!= -1 ? ret
: jxtest(0x85, addr
);
701 long o_jmp(long addr
)
703 os("\xe9", 1); /* jmp $addr */
704 oi(addr
- codeaddr() - 4, 4);
705 return codeaddr() - 4;
708 void o_filljmp(long addr
)
710 putint(buf
+ addr
, codeaddr() - addr
- 4, 4);
713 void o_call(int argc
, unsigned *bt
, unsigned ret_bt
)
717 for (i
= 0; i
< argc
; i
++)
718 tmp_pop(1, arg_regs
[i
]);
720 if (t
->flags
& LOC_SYM
) {
721 os("\xe8", 1); /* call $x */
722 out_rela(t
->addr
, codeaddr(), 1);
727 regop(CALL_REG
, 2, R_RAX
, 4);
729 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
733 tmp_push_reg(ret_bt
, R_RAX
);