8 /* variable location */
13 #define LOC_LOCAL 0x10
15 /* special registers */
19 #define REG_FORK R_RAX
30 /* x86_64 registers */
40 #define N_ARGS ARRAY_SIZE(argregs)
41 #define N_TMPS ARRAY_SIZE(tmpregs)
44 #define R_SAVED 0xf008
46 #define MIN(a, b) ((a) < (b) ? (a) : (b))
47 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
50 static char cs
[SECSIZE
]; /* code segment */
52 static char ds
[SECSIZE
]; /* data segment */
54 static long bsslen
; /* bss segment size */
56 static long sp
; /* stack pointer offset from R_RBP */
57 static long sp_max
; /* maximum stack pointer offset */
58 static long sp_tmp
; /* sp for the first tmp on the stack */
59 static long func_beg
; /* function address in CS */
60 static long func_fpsub
; /* stack pointer sub address in CS */
61 static int func_argc
; /* # of args */
62 static int func_vararg
; /* vararg function */
64 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
69 long off
; /* offset from a symbol or a local */
70 unsigned loc
; /* variable location */
71 unsigned bt
; /* type of address; zero when not a pointer */
75 /* arch-specific functions */
76 static void i_ldr(int l
, int rd
, int rn
, int off
, int bt
);
77 static void i_mov(int rd
, int rn
, int bt
);
78 static void i_add(int op
, int rd
, int rn
, int rm
);
79 static void i_shl(int op
, int rd
, int rm
, int rs
);
80 static void i_mul(int rd
, int rn
, int rm
);
81 static void i_div(int op
, int rd
, int rn
, int rm
);
82 static void i_cmp(int rn
, int rm
);
83 static int i_decodeable(long imm
);
84 static void i_add_imm(int op
, int rd
, int rn
, long n
);
85 static void i_shl_imm(int op
, int rd
, int rn
, long n
);
86 static void i_cmp_imm(int rn
, long n
);
87 static void i_add_anyimm(int rd
, int rn
, long n
);
88 static void i_num(int rd
, long n
);
89 static void i_sym(int rd
, char *sym
, int off
);
90 static void i_set(int op
, int rd
);
91 static void i_neg(int rd
);
92 static void i_not(int rd
);
93 static void i_lnot(int rd
);
94 static void i_zx(int rd
, int bits
);
95 static void i_sx(int rd
, int bits
);
96 static void i_b(void);
97 static void i_bz(int rn
, int z
);
98 static void i_b_fill(long src
, long dst
);
99 static void i_call(char *sym
, int off
);
100 static void i_call_reg(int rd
);
101 static void i_prolog(void);
102 static void i_epilog(void);
104 static struct tmp
*regs
[N_REGS
];
105 static int tmpregs
[] = {R_RAX
, R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
,
107 static int argregs
[] = {R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
109 /* labels and jmps */
110 #define MAXJMPS (1 << 14)
112 static long labels
[MAXJMPS
];
114 static long jmp_loc
[MAXJMPS
];
115 static int jmp_goal
[MAXJMPS
];
125 static void jmp_add(int id
)
127 if (njmps
>= MAXJMPS
)
128 err("nomem: MAXJMPS reached!\n");
129 jmp_loc
[njmps
] = cslen
- 4;
130 jmp_goal
[njmps
] = id
;
134 static void jmp_fill(void)
137 for (i
= 0; i
< njmps
; i
++)
138 i_b_fill(jmp_loc
[i
], labels
[jmp_goal
[i
]]);
141 /* generating code */
143 static void putint(char *s
, long n
, int l
)
151 static void os(void *s
, int n
)
154 cs
[cslen
++] = *(char *) (s
++);
157 static void oi(long n
, int l
)
165 static long sp_push(int size
)
173 static void tmp_mem(struct tmp
*tmp
)
176 if (tmp
->loc
!= LOC_REG
)
180 tmp
->addr
= -sp_push(LONGSZ
);
181 i_ldr(0, src
, REG_FP
, tmp
->addr
, LONGSZ
);
186 static void num_cast(struct tmp
*t
, unsigned bt
)
188 if (!(bt
& BT_SIGNED
) && BT_SZ(bt
) != LONGSZ
)
189 t
->addr
&= ((1l << (long) (BT_SZ(bt
) * 8)) - 1);
190 if (bt
& BT_SIGNED
&& BT_SZ(bt
) != LONGSZ
&&
191 t
->addr
> (1l << (BT_SZ(bt
) * 8 - 1)))
192 t
->addr
= -((1l << (BT_SZ(bt
) * 8)) - t
->addr
);
195 static void tmp_reg(struct tmp
*tmp
, int dst
, int deref
)
202 if (tmp
->loc
== LOC_NUM
) {
203 i_num(dst
, tmp
->addr
);
208 if (tmp
->loc
== LOC_SYM
) {
209 i_sym(dst
, tmp
->sym
, tmp
->off
);
214 if (tmp
->loc
== LOC_REG
) {
216 i_ldr(1, dst
, tmp
->addr
, 0, bt
);
217 else if (dst
!= tmp
->addr
)
218 i_mov(dst
, tmp
->addr
, LONGSZ
);
219 regs
[tmp
->addr
] = NULL
;
221 if (tmp
->loc
== LOC_LOCAL
) {
223 i_ldr(1, dst
, REG_FP
, tmp
->addr
+ tmp
->off
, bt
);
225 i_add_anyimm(dst
, REG_FP
, tmp
->addr
+ tmp
->off
);
227 if (tmp
->loc
== LOC_MEM
) {
228 i_ldr(1, dst
, REG_FP
, tmp
->addr
, LONGSZ
);
230 i_ldr(1, dst
, dst
, 0, bt
);
237 static void reg_free(int reg
)
242 for (i
= 0; i
< N_TMPS
; i
++)
243 if (!regs
[tmpregs
[i
]]) {
244 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
250 static void reg_for(int reg
, struct tmp
*t
)
252 if (regs
[reg
] && regs
[reg
] != t
)
256 static void tmp_mv(struct tmp
*t
, int reg
)
262 static void tmp_to(struct tmp
*t
, int reg
)
268 static void tmp_drop(int n
)
271 for (i
= ntmp
- n
; i
< ntmp
; i
++)
272 if (tmps
[i
].loc
== LOC_REG
)
273 regs
[tmps
[i
].addr
] = NULL
;
277 static void tmp_pop(int reg
)
279 struct tmp
*t
= TMP(0);
284 static struct tmp
*tmp_new(void)
286 return &tmps
[ntmp
++];
289 static void tmp_push(int reg
)
291 struct tmp
*t
= tmp_new();
298 void o_local(long addr
)
300 struct tmp
*t
= tmp_new();
309 struct tmp
*t
= tmp_new();
315 void o_sym(char *name
)
317 struct tmp
*t
= tmp_new();
318 strcpy(t
->sym
, name
);
324 void o_tmpdrop(int n
)
326 if (n
== -1 || n
> ntmp
)
336 /* make sure tmps remain intact after a conditional expression */
340 for (i
= 0; i
< ntmp
- 1; i
++)
344 void o_forkpush(void)
349 void o_forkjoin(void)
356 struct tmp
*t1
= TMP(0);
357 struct tmp
*t2
= TMP(1);
359 memcpy(&t
, t1
, sizeof(t
));
360 memcpy(t1
, t2
, sizeof(t
));
361 memcpy(t2
, &t
, sizeof(t
));
362 if (t1
->loc
== LOC_REG
)
364 if (t2
->loc
== LOC_REG
)
368 static int reg_get(int mask
)
371 for (i
= 0; i
< N_TMPS
; i
++)
372 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]])
374 for (i
= 0; i
< N_TMPS
; i
++)
375 if ((1 << tmpregs
[i
]) & mask
) {
376 reg_free(tmpregs
[i
]);
382 static int reg_fortmp(struct tmp
*t
, int notmask
)
384 if (t
->loc
== LOC_REG
&& !(notmask
& (1 << t
->addr
)))
386 return reg_get(~notmask
);
389 static void tmp_copy(struct tmp
*t1
)
391 struct tmp
*t2
= tmp_new();
392 memcpy(t2
, t1
, sizeof(*t1
));
393 if (!(t1
->loc
& (LOC_REG
| LOC_MEM
)))
395 if (t1
->loc
== LOC_MEM
) {
396 tmp_mv(t2
, reg_get(~0));
397 } else if (t1
->loc
== LOC_REG
) {
398 t2
->addr
= reg_fortmp(t2
, 1 << t1
->addr
);
399 i_mov(t2
->addr
, t1
->addr
, LONGSZ
);
409 void o_cast(unsigned bt
)
411 struct tmp
*t
= TMP(0);
412 if (!t
->bt
&& t
->loc
== LOC_NUM
) {
416 if (BT_SZ(bt
) != LONGSZ
) {
417 int reg
= reg_fortmp(t
, 0);
420 i_sx(reg
, BT_SZ(bt
) * 8);
422 i_zx(reg
, BT_SZ(bt
) * 8);
426 void o_func_beg(char *name
, int argc
, int global
, int vararg
)
428 out_sym(name
, (global
? OUT_GLOB
: 0) | OUT_CS
, cslen
, 0);
430 func_vararg
= vararg
;
438 memset(regs
, 0, sizeof(regs
));
441 void o_deref(unsigned bt
)
443 struct tmp
*t
= TMP(0);
445 tmp_to(t
, reg_fortmp(t
, 0));
451 struct tmp
*t
= TMP(0);
452 tmp_to(t
, reg_fortmp(t
, 0));
455 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
456 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
457 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
459 int o_popnum(long *c
)
461 struct tmp
*t
= TMP(0);
478 void o_func_end(void)
485 long o_mklocal(int sz
)
487 return sp_push(ALIGN(sz
, LONGSZ
));
490 void o_rmlocal(long addr
, int sz
)
492 sp
= addr
- ALIGN(sz
, LONGSZ
);
495 long o_arg2loc(int i
)
497 return -LONGSZ
* (i
+ 2);
500 void o_assign(unsigned bt
)
502 struct tmp
*t1
= TMP(0);
503 struct tmp
*t2
= TMP(1);
504 int r1
= reg_fortmp(t1
, 0);
505 int r2
= reg_fortmp(t2
, 1 << r1
);
510 if (t2
->loc
== LOC_LOCAL
) {
512 off
= t2
->addr
+ t2
->off
;
516 i_ldr(0, r1
, r2
, off
, bt
);
521 static long cu(int op
, long i
)
534 static int c_uop(int op
)
536 struct tmp
*t1
= TMP(0);
540 o_num(cu(op
, t1
->addr
));
544 static long cb(int op
, long a
, long b
)
569 return (unsigned long) a
>> b
;
586 static int c_bop(int op
)
588 struct tmp
*t1
= TMP(0);
589 struct tmp
*t2
= TMP(1);
590 int locs
= LOCAL_PTR(t1
) + LOCAL_PTR(t2
);
591 int syms
= SYM_PTR(t1
) + SYM_PTR(t2
);
592 int nums
= TMP_NUM(t1
) + TMP_NUM(t2
);
593 if (syms
+ locs
== 2 || syms
+ nums
+ locs
!= 2)
596 if ((op
& 0xff) != O_ADD
&& ((op
& 0xff) != O_SUB
|| TMP_NUM(t2
)))
599 long o1
= TMP_NUM(t1
) ? t1
->addr
: t1
->off
;
600 long o2
= TMP_NUM(t2
) ? t2
->addr
: t2
->off
;
601 long ret
= cb(op
, o2
, o1
);
607 long ret
= cb(op
, t2
->addr
, t1
->addr
);
616 int r1
= (op
& 0xff) == O_LNOT
? R_RAX
: reg_fortmp(TMP(0), 0);
633 static void bin_regs(int *r1
, int *r2
, int mask1
, int mask2
)
635 struct tmp
*t2
= TMP(0);
636 struct tmp
*t1
= TMP(1);
637 *r2
= reg_fortmp(t2
, ~mask1
);
639 *r1
= reg_fortmp(t1
, ~mask2
| (1 << *r2
));
644 static int bop_imm(int *r1
, long *n
, int swap
)
646 struct tmp
*t1
= TMP(0);
647 struct tmp
*t2
= TMP(1);
648 if (!TMP_NUM(t1
) && (!swap
|| !TMP_NUM(t2
)))
650 *n
= TMP_NUM(t1
) ? t1
->addr
: t2
->addr
;
651 if (!i_decodeable(*n
))
655 *r1
= reg_fortmp(t2
, 0);
661 static void bin_add(int op
)
665 if (!bop_imm(&r1
, &n
, (op
& 0xff) != O_SUB
)) {
666 i_add_imm(op
, r1
, r1
, n
);
668 bin_regs(&r1
, &r2
, R_TMPS
, R_TMPS
);
669 i_add(op
, r1
, r1
, r2
);
674 static void bin_shx(int op
)
678 if (!bop_imm(&r1
, &n
, 0)) {
679 i_shl_imm(op
, r1
, r1
, n
);
681 bin_regs(&r1
, &r2
, 1 << R_RCX
, R_TMPS
);
682 i_shl(op
, r1
, r1
, r2
);
687 static int log2a(unsigned long n
)
690 for (i
= 0; i
< LONGSZ
* 8; i
++)
693 if (i
== LONGSZ
* 8 || !(n
>> (i
+ 1)))
698 /* optimized version of mul/div/mod for powers of two */
699 static int mul_2(int op
)
701 struct tmp
*t1
= TMP(0);
702 struct tmp
*t2
= TMP(1);
706 if ((op
& 0xff) == O_MUL
&& t2
->loc
== LOC_NUM
&& !t2
->bt
)
708 if (t1
->loc
!= LOC_NUM
|| t1
->bt
)
714 if ((op
& 0xff) == O_MUL
) {
723 r2
= reg_fortmp(t2
, 0);
725 i_shl_imm(O_SHL
, r2
, r2
, p
);
732 r2
= reg_fortmp(t2
, 0);
734 i_shl_imm((op
& O_SIGNED
) | O_SHR
, r2
, r2
, p
);
744 r2
= reg_fortmp(t2
, 0);
752 static void mulop(int *r1
, int *r2
, int rop
)
754 struct tmp
*t1
= TMP(0);
755 struct tmp
*t2
= TMP(1);
756 if (t1
->loc
& LOC_REG
&& t1
->addr
!= R_RAX
&& t1
->addr
!= R_RDX
)
767 static void bin_mul(int op
)
772 mulop(&r1
, &r2
, (op
& 0xff) == O_MUL
? R_RDX
: R_RCX
);
773 if ((op
& 0xff) == O_MUL
) {
774 i_mul(R_RAX
, r1
, r2
);
777 if ((op
& 0xff) == O_DIV
) {
778 i_div(op
, R_RAX
, r1
, r2
);
781 if ((op
& 0xff) == O_MOD
) {
782 i_div(op
, R_RDX
, r1
, r2
);
787 static void bin_cmp(int op
)
791 if (!bop_imm(&r1
, &n
, (op
& 0xff) == O_EQ
|| (op
& 0xff) == O_NEQ
)) {
794 bin_regs(&r1
, &r2
, R_TMPS
, R_TMPS
);
807 if ((op
& 0xf0) == 0x00)
809 if ((op
& 0xf0) == 0x10)
811 if ((op
& 0xf0) == 0x20)
813 if ((op
& 0xf0) == 0x30)
819 struct tmp
*t0
= TMP(0);
820 struct tmp
*t1
= TMP(1);
821 struct tmp
*t2
= TMP(2);
825 os("\xfc\xf3\xa4", 3); /* cld; rep movs */
831 struct tmp
*t0
= TMP(0);
832 struct tmp
*t1
= TMP(1);
833 struct tmp
*t2
= TMP(2);
837 os("\xfc\xf3\xaa", 3); /* cld; rep stosb */
841 static void jxz(int id
, int z
)
843 int r
= reg_fortmp(TMP(0), 0);
865 void o_call(int argc
, int rets
)
869 int aregs
= MIN(N_ARGS
, argc
);
870 for (i
= 0; i
< N_TMPS
; i
++)
871 if (regs
[tmpregs
[i
]] && regs
[tmpregs
[i
]] - tmps
< ntmp
- argc
)
872 tmp_mem(regs
[tmpregs
[i
]]);
874 sp_push(LONGSZ
* (argc
- aregs
));
875 for (i
= argc
- 1; i
>= aregs
; --i
) {
876 int reg
= reg_fortmp(TMP(0), 0);
878 i_ldr(0, reg
, REG_SP
, (i
- aregs
) * LONGSZ
, LONGSZ
);
881 for (i
= aregs
- 1; i
>= 0; --i
)
882 tmp_to(TMP(aregs
- i
- 1), argregs
[i
]);
885 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
886 i_call(t
->sym
, t
->off
);
889 int reg
= reg_fortmp(t
, 0);
897 void o_mkbss(char *name
, int size
, int global
)
899 out_sym(name
, OUT_BSS
| (global
? OUT_GLOB
: 0), bsslen
, size
);
900 bsslen
+= ALIGN(size
, OUT_ALIGNMENT
);
903 #define MAXDATS (1 << 10)
904 static char dat_names
[MAXDATS
][NAMELEN
];
905 static int dat_offs
[MAXDATS
];
908 void *o_mkdat(char *name
, int size
, int global
)
910 void *addr
= ds
+ dslen
;
913 err("nomem: MAXDATS reached!\n");
914 strcpy(dat_names
[idx
], name
);
915 dat_offs
[idx
] = dslen
;
916 out_sym(name
, OUT_DS
| (global
? OUT_GLOB
: 0), dslen
, size
);
917 dslen
+= ALIGN(size
, OUT_ALIGNMENT
);
921 static int dat_off(char *name
)
924 for (i
= 0; i
< ndats
; i
++)
925 if (!strcmp(name
, dat_names
[i
]))
930 void o_datset(char *name
, int off
, unsigned bt
)
932 struct tmp
*t
= TMP(0);
933 int sym_off
= dat_off(name
) + off
;
934 if (t
->loc
== LOC_NUM
&& !t
->bt
) {
936 memcpy(ds
+ sym_off
, &t
->addr
, BT_SZ(bt
));
938 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
939 out_rel(t
->sym
, OUT_DS
, sym_off
);
940 memcpy(ds
+ sym_off
, &t
->off
, BT_SZ(bt
));
947 out_write(fd
, cs
, cslen
, ds
, dslen
);
950 /* X86 arch specific functions */
956 #define I_MOVSXD 0x63
970 #define OP2(o2, o1) (0x010000 | ((o2) << 8) | (o1))
971 #define O2(op) (((op) >> 8) & 0xff)
972 #define O1(op) ((op) & 0xff)
973 #define MODRM(m, r1, r2) ((m) << 6 | (r1) << 3 | (r2))
974 #define REX(r1, r2) (0x48 | (((r1) & 8) >> 1) | (((r2) & 8) >> 3))
976 /* for optimizing cmp + jmp */
977 #define OPT_ISCMP() (last_set + 7 == cslen)
978 #define OPT_CCOND() (cs[last_set + 1])
980 static long last_set
= -1;
982 static void op_x(int op
, int r1
, int r2
, int bt
)
1000 oi(sz
== 1 ? O1(op
) & ~0x1 : O1(op
), 1);
1005 /* op_*(): r=reg, m=mem, i=imm, s=sym */
1006 static void op_rm(int op
, int src
, int base
, int off
, int bt
)
1008 int dis
= off
== (char) off
? 1 : 4;
1009 int mod
= dis
== 4 ? 2 : 1;
1010 if (!off
&& (base
& 7) != R_RBP
)
1012 op_x(op
, src
, base
, bt
);
1013 oi(MODRM(mod
, src
& 0x07, base
& 0x07), 1);
1014 if ((base
& 7) == R_RSP
)
1020 static void op_rr(int op
, int src
, int dst
, int bt
)
1022 op_x(op
, src
, dst
, bt
);
1023 oi(MODRM(3, src
& 0x07, dst
& 0x07), 1);
1026 #define movrx_bt(bt) (((bt) == 4) ? 4 : LONGSZ)
1028 static int movrx_op(int bt
, int mov
)
1032 return bt
& BT_SIGNED
? I_MOVSXD
: mov
;
1034 return OP2(0x0f, bt
& BT_SIGNED
? 0xbf : 0xb7);
1036 return OP2(0x0f, bt
& BT_SIGNED
? 0xbe : 0xb6);
1040 static void mov_r2r(int r1
, int r2
, unsigned bt
)
1042 if (r1
!= r2
|| BT_SZ(bt
) != LONGSZ
)
1043 op_rr(movrx_op(bt
, I_MOV
), r1
, r2
, movrx_bt(bt
));
1046 static void mov_m2r(int dst
, int base
, int off
, int bt
)
1048 op_rm(movrx_op(bt
, I_MOVR
), dst
, base
, off
, movrx_bt(bt
));
1051 static void i_zx(int rd
, int bits
)
1054 i_shl_imm(O_SHL
, rd
, rd
, LONGSZ
* 8 - bits
);
1055 i_shl_imm(O_SHR
, rd
, rd
, LONGSZ
* 8 - bits
);
1057 mov_r2r(rd
, rd
, bits
>> 3);
1061 static void i_sx(int rd
, int bits
)
1063 mov_r2r(rd
, rd
, BT_SIGNED
| (bits
>> 3));
1066 static void i_add(int op
, int rd
, int rn
, int rm
)
1068 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1069 static int rx
[] = {0003, 0053, 0043, 0013, 0063};
1071 die("this is cisc!\n");
1072 op_rr(rx
[op
& 0x0f], rd
, rm
, LONGSZ
);
1075 static void i_add_imm(int op
, int rd
, int rn
, long n
)
1077 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1078 static int rx
[] = {0xc0, 0xe8, 0xe0, 0xc8, 0xf0};
1079 unsigned char s
[4] = {REX(0, rd
), 0x83, rx
[op
& 0x0f] | (rd
& 7), n
& 0xff};
1081 die("this is cisc!\n");
1085 static int i_decodeable(long imm
)
1087 return imm
<= 127 && imm
>= -128;
1090 static void i_num(int rd
, long n
)
1093 op_rr(I_XOR
, rd
, rd
, 4);
1096 if (n
< 0 && -n
<= 0xffffffff) {
1097 op_rr(I_MOVI
, 0, rd
, LONGSZ
);
1101 if (n
> 0 && n
<= 0xffffffff)
1103 op_x(I_MOVIR
+ (rd
& 7), 0, rd
, len
);
1108 static void i_add_anyimm(int rd
, int rn
, long n
)
1110 op_rm(I_LEA
, rd
, rn
, n
, LONGSZ
);
1113 static void i_mul(int rd
, int rn
, int rm
)
1117 op_rr(I_MUL
, 4, rn
, LONGSZ
);
1120 static void i_div(int op
, int rd
, int rn
, int rm
)
1124 op_x(I_CQO
, R_RAX
, R_RDX
, LONGSZ
);
1128 op_rr(I_MUL
, op
& O_SIGNED
? 7 : 6, rn
, LONGSZ
);
1131 static void i_tst(int rn
, int rm
)
1133 op_rr(I_TST
, rn
, rm
, LONGSZ
);
1136 static void i_cmp(int rn
, int rm
)
1138 op_rr(I_CMP
, rn
, rm
, LONGSZ
);
1141 static void i_cmp_imm(int rn
, long n
)
1143 unsigned char s
[4] = {REX(0, rn
), 0x83, 0xf8 | rn
, n
& 0xff};
1147 static void i_set(int op
, int rd
)
1149 /* lt, gt, le, ge, eq, neq */
1150 static int ucond
[] = {0x92, 0x97, 0x96, 0x93, 0x94, 0x95};
1151 static int scond
[] = {0x9c, 0x9f, 0x9e, 0x9d, 0x94, 0x95};
1152 int cond
= op
& O_SIGNED
? scond
[op
& 0x0f] : ucond
[op
& 0x0f];
1153 char set
[] = "\x0f\x00\xc0";
1155 die("set works only with R_RAX\n");
1158 os(set
, 3); /* setl al */
1159 os("\x48\x0f\xb6\xc0", 4); /* movzx rax, al */
1162 static void i_shl(int op
, int rd
, int rm
, int rs
)
1165 if ((op
& 0x0f) == 1)
1166 sm
= op
& O_SIGNED
? 7 : 5;
1168 die("this is cisc!\n");
1169 op_rr(I_SHX
, sm
, rd
, LONGSZ
);
1172 static void i_shl_imm(int op
, int rd
, int rn
, long n
)
1174 int sm
= (op
& 0x1) ? (op
& O_SIGNED
? 0xf8 : 0xe8) : 0xe0 ;
1175 char s
[4] = {REX(0, rn
), 0xc1, sm
| (rn
& 7), n
& 0xff};
1177 die("this is cisc!\n");
1181 static void i_mov(int rd
, int rn
, int bt
)
1183 op_rr(movrx_op(bt
, I_MOVR
), rd
, rn
, movrx_bt(bt
));
1186 static void i_ldr(int l
, int rd
, int rn
, int off
, int bt
)
1189 mov_m2r(rd
, rn
, off
, bt
);
1191 op_rm(I_MOV
, rd
, rn
, off
, bt
);
1194 static void i_sym(int rd
, char *sym
, int off
)
1196 op_x(I_MOVIR
+ (rd
& 7), 0, rd
, LONGSZ
);
1197 out_rel(sym
, OUT_CS
, cslen
);
1201 static void i_neg(int rd
)
1203 op_rr(I_NOT
, 3, rd
, LONGSZ
);
1206 static void i_not(int rd
)
1208 op_rr(I_NOT
, 2, rd
, LONGSZ
);
1211 static void i_lnot(int rd
)
1214 cs
[last_set
+ 1] ^= 0x01;
1216 char cmp
[] = "\x00\x83\xf8\x00";
1217 cmp
[0] = REX(0, rd
);
1219 os(cmp
, 4); /* cmp rax, 0 */
1224 static void jx(int x
, long addr
)
1226 char op
[2] = {0x0f};
1228 os(op
, 2); /* jx $addr */
1229 oi(addr
- cslen
- 4, 4);
1232 static void i_bz(int rn
, int z
)
1235 int cond
= OPT_CCOND();
1237 jx((!z
? cond
: cond
^ 0x01) & ~0x10, 0);
1241 jx(z
? 0x84 : 0x85, 0);
1245 static void i_b(void)
1247 os("\xe9", 1); /* jmp $addr */
1251 static void i_b_fill(long src
, long dst
)
1253 putint((void *) (cs
+ src
), (dst
- src
) - 4, 4);
1256 static void i_call_reg(int rd
)
1258 op_rr(I_CALL
, 2, rd
, LONGSZ
);
1261 static void i_call(char *sym
, int off
)
1263 os("\xe8", 1); /* call $x */
1264 out_rel(sym
, OUT_CS
| OUT_REL
, cslen
);
1268 static void i_push(int reg
)
1270 op_x(I_PUSH
| (reg
& 0x7), 0, reg
, 4);
1273 static void i_pop(int reg
)
1275 op_x(I_POP
| (reg
& 0x7), 0, reg
, 4);
1278 static void i_saveargs(void)
1281 int saved
= func_vararg
? N_ARGS
: MIN(N_ARGS
, func_argc
);
1282 os("\x58", 1); /* pop rax */
1283 for (i
= saved
- 1; i
>= 0; i
--)
1285 os("\x50", 1); /* push rax */
1288 static void i_prolog(void)
1292 os("\x55", 1); /* push rbp */
1293 os("\x48\x89\xe5", 3); /* mov rbp, rsp */
1294 os("\x48\x81\xec", 3); /* sub rsp, $xxx */
1299 static void i_epilog(void)
1301 int saved
= func_vararg
? N_ARGS
: MIN(N_ARGS
, func_argc
);
1302 int diff
= ALIGN(sp_max
, 16) + (saved
& 1 ? 8 : 0);
1304 putint(cs
+ func_fpsub
, diff
, 4);
1306 os("\xc9", 1); /* leave */
1308 os("\xc2", 1); /* ret n */
1309 oi(saved
* LONGSZ
, 2);
1311 os("\xc3", 1); /* ret */