2 * i386 specific functions for TCC assembler
4 * Copyright (c) 2001, 2002 Fabrice Bellard
5 * Copyright (c) 2009 Frédéric Feret (x86_64 support)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #define MAX_OPERANDS 3
27 #define TOK_ASM_first TOK_ASM_clc
28 #define TOK_ASM_last TOK_ASM_emms
29 #define TOK_ASM_alllast TOK_ASM_subps
31 #define OPC_B 0x01 /* only used with OPC_WL */
32 #define OPC_WL 0x02 /* accepts w, l or no suffix */
33 #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
34 #define OPC_REG 0x04 /* register is added to opcode */
35 #define OPC_MODRM 0x08 /* modrm encoding */
37 #define OPCT_MASK 0x70
38 #define OPC_FWAIT 0x10 /* add fwait opcode */
39 #define OPC_SHIFT 0x20 /* shift opcodes */
40 #define OPC_ARITH 0x30 /* arithmetic opcodes */
41 #define OPC_FARITH 0x40 /* FPU arithmetic opcodes */
42 #define OPC_TEST 0x50 /* test opcodes */
43 #define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
45 #define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */
46 #define OPC_48 0x200 /* Always has REX prefix */
47 #ifdef TCC_TARGET_X86_64
48 # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
49 # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
50 # define OPC_WLX OPC_WLQ
51 # define OPC_BWLX OPC_BWLQ
53 # define OPC_WLX OPC_WL
54 # define OPC_BWLX OPC_BWL
57 #define OPC_GROUP_SHIFT 13
59 /* in order to compress the operand type, we use specific operands and
62 OPT_REG8
=0, /* warning: value is hardcoded from TOK_ASM_xxx */
63 OPT_REG16
, /* warning: value is hardcoded from TOK_ASM_xxx */
64 OPT_REG32
, /* warning: value is hardcoded from TOK_ASM_xxx */
65 #ifdef TCC_TARGET_X86_64
66 OPT_REG64
, /* warning: value is hardcoded from TOK_ASM_xxx */
68 OPT_MMX
, /* warning: value is hardcoded from TOK_ASM_xxx */
69 OPT_SSE
, /* warning: value is hardcoded from TOK_ASM_xxx */
70 OPT_CR
, /* warning: value is hardcoded from TOK_ASM_xxx */
71 OPT_TR
, /* warning: value is hardcoded from TOK_ASM_xxx */
72 OPT_DB
, /* warning: value is hardcoded from TOK_ASM_xxx */
75 #ifdef TCC_TARGET_X86_64
76 OPT_REG8_LOW
, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but
77 with REX prefix, not used in insn templates */
83 #ifdef TCC_TARGET_X86_64
86 OPT_EAX
, /* %al, %ax, %eax or %rax register */
87 OPT_ST0
, /* %st(0) register */
88 OPT_CL
, /* %cl register */
89 OPT_DX
, /* %dx register */
90 OPT_ADDR
, /* OP_EA with only offset */
91 OPT_INDIR
, /* *(expr) */
94 OPT_IM
, /* IM8 | IM16 | IM32 */
95 OPT_REG
, /* REG8 | REG16 | REG32 | REG64 */
96 OPT_REGW
, /* REG16 | REG32 | REG64 */
97 OPT_IMW
, /* IM16 | IM32 */
98 OPT_MMXSSE
, /* MMX | SSE */
99 OPT_DISP
, /* Like OPT_ADDR, but emitted as displacement (for jumps) */
100 OPT_DISP8
, /* Like OPT_ADDR, but only 8bit (short jumps) */
101 /* can be ored with any OPT_xxx */
105 #define OP_REG8 (1 << OPT_REG8)
106 #define OP_REG16 (1 << OPT_REG16)
107 #define OP_REG32 (1 << OPT_REG32)
108 #define OP_MMX (1 << OPT_MMX)
109 #define OP_SSE (1 << OPT_SSE)
110 #define OP_CR (1 << OPT_CR)
111 #define OP_TR (1 << OPT_TR)
112 #define OP_DB (1 << OPT_DB)
113 #define OP_SEG (1 << OPT_SEG)
114 #define OP_ST (1 << OPT_ST)
115 #define OP_IM8 (1 << OPT_IM8)
116 #define OP_IM8S (1 << OPT_IM8S)
117 #define OP_IM16 (1 << OPT_IM16)
118 #define OP_IM32 (1 << OPT_IM32)
119 #define OP_EAX (1 << OPT_EAX)
120 #define OP_ST0 (1 << OPT_ST0)
121 #define OP_CL (1 << OPT_CL)
122 #define OP_DX (1 << OPT_DX)
123 #define OP_ADDR (1 << OPT_ADDR)
124 #define OP_INDIR (1 << OPT_INDIR)
125 #ifdef TCC_TARGET_X86_64
126 # define OP_REG64 (1 << OPT_REG64)
127 # define OP_REG8_LOW (1 << OPT_REG8_LOW)
128 # define OP_IM64 (1 << OPT_IM64)
129 # define OP_EA32 (OP_EA << 1)
132 # define OP_REG8_LOW 0
137 #define OP_EA 0x40000000
138 #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
140 #ifdef TCC_TARGET_X86_64
141 # define TREG_XAX TREG_RAX
142 # define TREG_XCX TREG_RCX
143 # define TREG_XDX TREG_RDX
145 # define TREG_XAX TREG_EAX
146 # define TREG_XCX TREG_ECX
147 # define TREG_XDX TREG_EDX
150 typedef struct ASMInstr
{
155 uint8_t op_type
[MAX_OPERANDS
]; /* see OP_xxx */
158 typedef struct Operand
{
160 int8_t reg
; /* register, -1 if none */
161 int8_t reg2
; /* second register, -1 if none */
166 static const uint8_t reg_to_size
[9] = {
171 #ifdef TCC_TARGET_X86_64
175 0, 0, 1, 0, 2, 0, 0, 0, 3
178 #define NB_TEST_OPCODES 30
180 static const uint8_t test_bits
[NB_TEST_OPCODES
] = {
213 static const uint8_t segment_prefixes
[] = {
222 static const ASMInstr asm_instrs
[] = {
224 /* This removes a 0x0f in the second byte */
225 #define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o)))
226 /* This constructs instr_type from opcode, type and group. */
227 #define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
228 #define DEF_ASM_OP0(name, opcode)
229 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } },
230 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
231 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
232 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }},
233 #ifdef TCC_TARGET_X86_64
234 # include "x86_64-asm.h"
236 # include "i386-asm.h"
242 static const uint16_t op0_codes
[] = {
244 #define DEF_ASM_OP0(x, opcode) opcode,
245 #define DEF_ASM_OP0L(name, opcode, group, instr_type)
246 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
247 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
248 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
249 #ifdef TCC_TARGET_X86_64
250 # include "x86_64-asm.h"
252 # include "i386-asm.h"
256 static inline int get_reg_shift(TCCState
*s1
)
259 v
= asm_int_expr(s1
);
274 expect("1, 2, 4 or 8 constant");
281 #ifdef TCC_TARGET_X86_64
282 static int asm_parse_numeric_reg(int t
, unsigned int *type
)
285 if (t
>= TOK_IDENT
&& t
< tok_ident
) {
286 const char *s
= table_ident
[t
- TOK_IDENT
]->str
;
295 /* Don't allow leading '0'. */
296 if ((c
= *s
++) >= '1' && c
<= '9')
300 if ((c
= *s
) >= '0' && c
<= '5')
301 s
++, reg
= reg
* 10 + c
- '0';
306 else if (*type
!= OP_REG64
)
308 else if (c
== 'b' && !s
[1])
310 else if (c
== 'w' && !s
[1])
312 else if (c
== 'd' && !s
[1])
321 static int asm_parse_reg(unsigned int *type
)
328 if (tok
>= TOK_ASM_eax
&& tok
<= TOK_ASM_edi
) {
329 reg
= tok
- TOK_ASM_eax
;
331 #ifdef TCC_TARGET_X86_64
332 } else if (tok
>= TOK_ASM_rax
&& tok
<= TOK_ASM_rdi
) {
333 reg
= tok
- TOK_ASM_rax
;
335 } else if (tok
== TOK_ASM_rip
) {
336 reg
= -2; /* Probably should use different escape code. */
338 } else if ((reg
= asm_parse_numeric_reg(tok
, type
)) >= 0
339 && (*type
== OP_REG32
|| *type
== OP_REG64
)) {
350 static void parse_operand(TCCState
*s1
, Operand
*op
)
364 if (tok
>= TOK_ASM_al
&& tok
<= TOK_ASM_db7
) {
365 reg
= tok
- TOK_ASM_al
;
366 op
->type
= 1 << (reg
>> 3); /* WARNING: do not change constant order */
368 if ((op
->type
& OP_REG
) && op
->reg
== TREG_XAX
)
370 else if (op
->type
== OP_REG8
&& op
->reg
== TREG_XCX
)
372 else if (op
->type
== OP_REG16
&& op
->reg
== TREG_XDX
)
374 } else if (tok
>= TOK_ASM_dr0
&& tok
<= TOK_ASM_dr7
) {
376 op
->reg
= tok
- TOK_ASM_dr0
;
377 } else if (tok
>= TOK_ASM_es
&& tok
<= TOK_ASM_gs
) {
379 op
->reg
= tok
- TOK_ASM_es
;
380 } else if (tok
== TOK_ASM_st
) {
386 if (tok
!= TOK_PPNUM
)
390 if ((unsigned)reg
>= 8 || p
[1] != '\0')
399 #ifdef TCC_TARGET_X86_64
400 } else if (tok
>= TOK_ASM_spl
&& tok
<= TOK_ASM_dil
) {
401 op
->type
= OP_REG8
| OP_REG8_LOW
;
402 op
->reg
= 4 + tok
- TOK_ASM_spl
;
403 } else if ((op
->reg
= asm_parse_numeric_reg(tok
, &op
->type
)) >= 0) {
408 tcc_error("unknown register %%%s", get_tok_str(tok
, &tokc
));
412 } else if (tok
== '$') {
419 if (op
->e
.v
== (uint8_t)op
->e
.v
)
421 if (op
->e
.v
== (int8_t)op
->e
.v
)
423 if (op
->e
.v
== (uint16_t)op
->e
.v
)
425 #ifdef TCC_TARGET_X86_64
426 if (op
->e
.v
!= (int32_t)op
->e
.v
&& op
->e
.v
!= (uint32_t)op
->e
.v
)
431 /* address(reg,reg2,shift) with all variants */
446 /* bracketed offset expression */
457 unsigned int type
= 0;
460 op
->reg
= asm_parse_reg(&type
);
465 op
->reg2
= asm_parse_reg(&type
);
469 op
->shift
= get_reg_shift(s1
);
476 if (op
->reg
== -1 && op
->reg2
== -1)
482 /* XXX: unify with C code output ? */
483 ST_FUNC
void gen_expr32(ExprValue
*pe
)
486 /* If PC-relative, always set VT_SYM, even without symbol,
487 so as to force a relocation to be emitted. */
488 gen_addrpc32(VT_SYM
, pe
->sym
, pe
->v
);
490 gen_addr32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
493 #ifdef TCC_TARGET_X86_64
494 ST_FUNC
void gen_expr64(ExprValue
*pe
)
496 gen_addr64(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
500 /* XXX: unify with C code output ? */
501 static void gen_disp32(ExprValue
*pe
)
504 ElfSym
*esym
= elfsym(sym
);
505 if (esym
&& esym
->st_shndx
== cur_text_section
->sh_num
) {
506 /* same section: we can output an absolute value. Note
507 that the TCC compiler behaves differently here because
508 it always outputs a relocation to ease (future) code
509 elimination in the linker */
510 gen_le32(pe
->v
+ esym
->st_value
- ind
- 4);
512 if (sym
&& sym
->type
.t
== VT_VOID
) {
513 sym
->type
.t
= VT_FUNC
;
514 sym
->type
.ref
= NULL
;
516 gen_addrpc32(VT_SYM
, sym
, pe
->v
);
520 /* generate the modrm operand */
521 static inline int asm_modrm(int reg
, Operand
*op
)
523 int mod
, reg1
, reg2
, sib_reg1
;
525 if (op
->type
& (OP_REG
| OP_MMX
| OP_SSE
)) {
526 g(0xc0 + (reg
<< 3) + op
->reg
);
527 } else if (op
->reg
== -1 && op
->reg2
== -1) {
528 /* displacement only */
529 #ifdef TCC_TARGET_X86_64
530 g(0x04 + (reg
<< 3));
533 g(0x05 + (reg
<< 3));
536 #ifdef TCC_TARGET_X86_64
537 } else if (op
->reg
== -2) {
538 ExprValue
*pe
= &op
->e
;
539 g(0x05 + (reg
<< 3));
540 gen_addrpc32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
545 /* fist compute displacement encoding */
546 if (sib_reg1
== -1) {
549 } else if (op
->e
.v
== 0 && !op
->e
.sym
&& op
->reg
!= 5) {
551 } else if (op
->e
.v
== (int8_t)op
->e
.v
&& !op
->e
.sym
) {
556 /* compute if sib byte needed */
560 g(mod
+ (reg
<< 3) + reg1
);
565 reg2
= 4; /* indicate no index */
566 g((op
->shift
<< 6) + (reg2
<< 3) + sib_reg1
);
571 } else if (mod
== 0x80 || op
->reg
== -1) {
578 #ifdef TCC_TARGET_X86_64
584 static void asm_rex(int width64
, Operand
*ops
, int nb_ops
, int *op_type
,
587 unsigned char rex
= width64
? 0x48 : 0;
588 int saw_high_8bit
= 0;
591 /* No mod/rm byte, but we might have a register op nevertheless
592 (we will add it to the opcode later). */
593 for(i
= 0; i
< nb_ops
; i
++) {
594 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
595 if (ops
[i
].reg
>= 8) {
598 } else if (ops
[i
].type
& OP_REG8_LOW
)
600 else if (ops
[i
].type
& OP_REG8
&& ops
[i
].reg
>= 4)
601 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
602 saw_high_8bit
= ops
[i
].reg
;
608 if (ops
[regi
].reg
>= 8) {
611 } else if (ops
[regi
].type
& OP_REG8_LOW
)
613 else if (ops
[regi
].type
& OP_REG8
&& ops
[regi
].reg
>= 4)
614 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
615 saw_high_8bit
= ops
[regi
].reg
;
617 if (ops
[rmi
].type
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_EA
)) {
618 if (ops
[rmi
].reg
>= 8) {
621 } else if (ops
[rmi
].type
& OP_REG8_LOW
)
623 else if (ops
[rmi
].type
& OP_REG8
&& ops
[rmi
].reg
>= 4)
624 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
625 saw_high_8bit
= ops
[rmi
].reg
;
627 if (ops
[rmi
].type
& OP_EA
&& ops
[rmi
].reg2
>= 8) {
634 tcc_error("can't encode register %%%ch when REX prefix is required",
635 "acdb"[saw_high_8bit
-4]);
642 static void maybe_print_stats (void)
647 /* print stats about opcodes */
649 const struct ASMInstr
*pa
;
652 int nb_op_vals
, i
, j
;
656 memset(freq
, 0, sizeof(freq
));
657 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
659 //for(i=0;i<pa->nb_ops;i++) {
660 for(j
=0;j
<nb_op_vals
;j
++) {
661 //if (pa->op_type[i] == op_vals[j])
662 if (pa
->instr_type
== op_vals
[j
])
665 //op_vals[nb_op_vals++] = pa->op_type[i];
666 op_vals
[nb_op_vals
++] = pa
->instr_type
;
670 for(i
=0;i
<nb_op_vals
;i
++) {
672 //if ((v & (v - 1)) != 0)
673 printf("%3d: %08x\n", i
, v
);
675 printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
676 (int)sizeof(asm_instrs
),
677 (int)sizeof(asm_instrs
) / (int)sizeof(ASMInstr
),
678 freq
[0], freq
[1], freq
[2], freq
[3]);
682 ST_FUNC
void asm_opcode(TCCState
*s1
, int opcode
)
685 int i
, modrm_index
, modreg_index
, reg
, v
, op1
, seg_prefix
, pc
;
687 Operand ops
[MAX_OPERANDS
], *pop
;
688 int op_type
[3]; /* decoded op type */
689 int alltypes
; /* OR of all operand types */
692 #ifdef TCC_TARGET_X86_64
697 /* force synthetic ';' after prefix instruction, so we can handle */
698 /* one-line things like "rep stosb" instead of only "rep\nstosb" */
699 if (opcode
>= TOK_ASM_wait
&& opcode
<= TOK_ASM_repnz
)
708 if (tok
== ';' || tok
== TOK_LINEFEED
)
710 if (nb_ops
>= MAX_OPERANDS
) {
711 tcc_error("incorrect number of operands");
713 parse_operand(s1
, pop
);
715 if (pop
->type
!= OP_SEG
|| seg_prefix
)
716 tcc_error("incorrect prefix");
717 seg_prefix
= segment_prefixes
[pop
->reg
];
719 parse_operand(s1
, pop
);
720 if (!(pop
->type
& OP_EA
)) {
721 tcc_error("segment prefix must be followed by memory reference");
731 s
= 0; /* avoid warning */
734 /* optimize matching by using a lookup table (no hashing is needed
736 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
737 int it
= pa
->instr_type
& OPCT_MASK
;
739 if (it
== OPC_FARITH
) {
740 v
= opcode
- pa
->sym
;
741 if (!((unsigned)v
< 8 * 6 && (v
% 6) == 0))
743 } else if (it
== OPC_ARITH
) {
744 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 8*NBWLX
))
746 s
= (opcode
- pa
->sym
) % NBWLX
;
747 if ((pa
->instr_type
& OPC_BWLX
) == OPC_WLX
)
749 /* We need to reject the xxxb opcodes that we accepted above.
750 Note that pa->sym for WLX opcodes is the 'w' token,
751 to get the 'b' token subtract one. */
752 if (((opcode
- pa
->sym
+ 1) % NBWLX
) == 0)
756 } else if (it
== OPC_SHIFT
) {
757 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 7*NBWLX
))
759 s
= (opcode
- pa
->sym
) % NBWLX
;
760 } else if (it
== OPC_TEST
) {
761 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NB_TEST_OPCODES
))
763 /* cmovxx is a test opcode but accepts multiple sizes.
764 The suffixes aren't encoded in the table, instead we
765 simply force size autodetection always and deal with suffixed
766 variants below when we don't find e.g. "cmovzl". */
767 if (pa
->instr_type
& OPC_WLX
)
769 } else if (pa
->instr_type
& OPC_B
) {
770 #ifdef TCC_TARGET_X86_64
771 /* Some instructions don't have the full size but only
772 bwl form. insb e.g. */
773 if ((pa
->instr_type
& OPC_WLQ
) != OPC_WLQ
774 && !(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
777 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
))
779 s
= opcode
- pa
->sym
;
780 } else if (pa
->instr_type
& OPC_WLX
) {
781 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
783 s
= opcode
- pa
->sym
+ 1;
785 if (pa
->sym
!= opcode
)
788 if (pa
->nb_ops
!= nb_ops
)
790 #ifdef TCC_TARGET_X86_64
791 /* Special case for moves. Selecting the IM64->REG64 form
792 should only be done if we really have an >32bit imm64, and that
793 is hardcoded. Ignore it here. */
794 if (pa
->opcode
== 0xb0 && ops
[0].type
!= OP_IM64
795 && (ops
[1].type
& OP_REG
) == OP_REG64
796 && !(pa
->instr_type
& OPC_0F
))
799 /* now decode and check each operand */
801 for(i
= 0; i
< nb_ops
; i
++) {
803 op1
= pa
->op_type
[i
];
807 v
= OP_IM8
| OP_IM16
| OP_IM32
;
810 v
= OP_REG8
| OP_REG16
| OP_REG32
| OP_REG64
;
813 v
= OP_REG16
| OP_REG32
| OP_REG64
;
816 v
= OP_IM16
| OP_IM32
;
832 if ((ops
[i
].type
& v
) == 0)
834 alltypes
|= ops
[i
].type
;
836 /* all is matching ! */
841 if (opcode
>= TOK_ASM_first
&& opcode
<= TOK_ASM_last
) {
843 b
= op0_codes
[opcode
- TOK_ASM_first
];
848 } else if (opcode
<= TOK_ASM_alllast
) {
849 tcc_error("bad operand with opcode '%s'",
850 get_tok_str(opcode
, NULL
));
852 /* Special case for cmovcc, we accept size suffixes but ignore
853 them, but we don't want them to blow up our tables. */
854 TokenSym
*ts
= table_ident
[opcode
- TOK_IDENT
];
856 && strchr("wlq", ts
->str
[ts
->len
-1])
857 && !memcmp(ts
->str
, "cmov", 4)) {
858 opcode
= tok_alloc(ts
->str
, ts
->len
-1)->tok
;
861 tcc_error("unknown opcode '%s'", ts
->str
);
864 /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
866 #ifdef TCC_TARGET_X86_64
867 /* XXX the autosize should rather be zero, to not have to adjust this
869 if ((pa
->instr_type
& OPC_BWLQ
) == OPC_B
)
873 /* Check for register operands providing hints about the size.
874 Start from the end, i.e. destination operands. This matters
875 only for opcodes accepting different sized registers, lar and lsl
877 for(i
= nb_ops
- 1; s
== autosize
&& i
>= 0; i
--) {
878 if ((ops
[i
].type
& OP_REG
) && !(op_type
[i
] & (OP_CL
| OP_DX
)))
879 s
= reg_to_size
[ops
[i
].type
& OP_REG
];
882 if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
883 (ops
[0].type
& (OP_SEG
| OP_IM8S
| OP_IM32
)))
885 else if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
886 (ops
[0].type
& OP_EA
))
889 tcc_error("cannot infer opcode suffix");
893 #ifdef TCC_TARGET_X86_64
894 /* Generate addr32 prefix if needed */
895 for(i
= 0; i
< nb_ops
; i
++) {
896 if (ops
[i
].type
& OP_EA32
) {
902 /* generate data16 prefix if needed */
907 /* accepting mmx+sse in all operands --> needs 0x66 to
908 switch to sse mode. Accepting only sse in an operand --> is
909 already SSE insn and needs 0x66/f2/f3 handling. */
910 for (i
= 0; i
< nb_ops
; i
++)
911 if ((op_type
[i
] & (OP_MMX
| OP_SSE
)) == (OP_MMX
| OP_SSE
)
912 && ops
[i
].type
& OP_SSE
)
917 #ifdef TCC_TARGET_X86_64
919 if (pa
->instr_type
& OPC_48
)
921 else if (s
== 3 || (alltypes
& OP_REG64
)) {
922 /* generate REX prefix */
924 for(i
= 0; i
< nb_ops
; i
++) {
925 if (op_type
[i
] == OP_REG64
&& pa
->opcode
!= 0xb8) {
926 /* If only 64bit regs are accepted in one operand
927 this is a default64 instruction without need for
928 REX prefixes, except for movabs(0xb8). */
933 /* XXX find better encoding for the default64 instructions. */
934 if (((opcode
!= TOK_ASM_push
&& opcode
!= TOK_ASM_pop
935 && opcode
!= TOK_ASM_pushw
&& opcode
!= TOK_ASM_pushl
936 && opcode
!= TOK_ASM_pushq
&& opcode
!= TOK_ASM_popw
937 && opcode
!= TOK_ASM_popl
&& opcode
!= TOK_ASM_popq
938 && opcode
!= TOK_ASM_call
&& opcode
!= TOK_ASM_jmp
))
944 /* now generates the operation */
945 if (OPCT_IS(pa
->instr_type
, OPC_FWAIT
))
951 if (pa
->instr_type
& OPC_0F
)
952 v
= ((v
& ~0xff) << 8) | 0x0f00 | (v
& 0xff);
953 if ((v
== 0x69 || v
== 0x6b) && nb_ops
== 2) {
954 /* kludge for imul $im, %reg */
957 op_type
[2] = op_type
[1];
958 } else if (v
== 0xcd && ops
[0].e
.v
== 3 && !ops
[0].e
.sym
) {
959 v
--; /* int $3 case */
961 } else if ((v
== 0x06 || v
== 0x07)) {
962 if (ops
[0].reg
>= 4) {
963 /* push/pop %fs or %gs */
964 v
= 0x0fa0 + (v
- 0x06) + ((ops
[0].reg
- 4) << 3);
966 v
+= ops
[0].reg
<< 3;
969 } else if (v
<= 0x05) {
971 v
+= ((opcode
- TOK_ASM_addb
) / NBWLX
) << 3;
972 } else if ((pa
->instr_type
& (OPCT_MASK
| OPC_MODRM
)) == OPC_FARITH
) {
974 v
+= ((opcode
- pa
->sym
) / 6) << 3;
977 /* search which operand will be used for modrm */
980 if (pa
->instr_type
& OPC_MODRM
) {
982 /* A modrm opcode without operands is a special case (e.g. mfence).
983 It has a group and acts as if there's an register operand 0
986 ops
[i
].type
= OP_REG
;
990 /* first look for an ea operand */
991 for(i
= 0;i
< nb_ops
; i
++) {
992 if (op_type
[i
] & OP_EA
)
995 /* then if not found, a register or indirection (shift instructions) */
996 for(i
= 0;i
< nb_ops
; i
++) {
997 if (op_type
[i
] & (OP_REG
| OP_MMX
| OP_SSE
| OP_INDIR
))
1001 tcc_error("bad op table");
1005 /* if a register is used in another operand then it is
1006 used instead of group */
1007 for(i
= 0;i
< nb_ops
; i
++) {
1009 if (i
!= modrm_index
&&
1010 (t
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_TR
| OP_DB
| OP_SEG
))) {
1016 #ifdef TCC_TARGET_X86_64
1017 asm_rex (rex64
, ops
, nb_ops
, op_type
, modreg_index
, modrm_index
);
1020 if (pa
->instr_type
& OPC_REG
) {
1021 /* mov $im, %reg case */
1022 if (v
== 0xb0 && s
>= 1)
1024 for(i
= 0; i
< nb_ops
; i
++) {
1025 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
1031 if (pa
->instr_type
& OPC_B
)
1033 if (nb_ops
== 1 && pa
->op_type
[0] == OPT_DISP8
) {
1037 /* see if we can really generate the jump with a byte offset */
1038 esym
= elfsym(ops
[0].e
.sym
);
1039 if (!esym
|| esym
->st_shndx
!= cur_text_section
->sh_num
)
1041 jmp_disp
= ops
[0].e
.v
+ esym
->st_value
- ind
- 2 - (v
>= 0xff);
1042 if (jmp_disp
== (int8_t)jmp_disp
) {
1043 /* OK to generate jump */
1045 ops
[0].e
.v
= jmp_disp
;
1046 op_type
[0] = OP_IM8S
;
1049 /* long jump will be allowed. need to modify the
1051 if (v
== 0xeb) /* jmp */
1053 else if (v
== 0x70) /* jcc */
1056 tcc_error("invalid displacement");
1059 if (OPCT_IS(pa
->instr_type
, OPC_TEST
))
1060 v
+= test_bits
[opcode
- pa
->sym
];
1064 op1
= (v
>> 8) & 0xff;
1069 if (OPCT_IS(pa
->instr_type
, OPC_SHIFT
)) {
1070 reg
= (opcode
- pa
->sym
) / NBWLX
;
1073 } else if (OPCT_IS(pa
->instr_type
, OPC_ARITH
)) {
1074 reg
= (opcode
- pa
->sym
) / NBWLX
;
1075 } else if (OPCT_IS(pa
->instr_type
, OPC_FARITH
)) {
1076 reg
= (opcode
- pa
->sym
) / 6;
1078 reg
= (pa
->instr_type
>> OPC_GROUP_SHIFT
) & 7;
1082 if (pa
->instr_type
& OPC_MODRM
) {
1083 /* if a register is used in another operand then it is
1084 used instead of group */
1085 if (modreg_index
>= 0)
1086 reg
= ops
[modreg_index
].reg
;
1087 pc
= asm_modrm(reg
, &ops
[modrm_index
]);
1090 /* emit constants */
1091 #ifndef TCC_TARGET_X86_64
1092 if (!(pa
->instr_type
& OPC_0F
)
1093 && (pa
->opcode
== 0x9a || pa
->opcode
== 0xea)) {
1094 /* ljmp or lcall kludge */
1095 gen_expr32(&ops
[1].e
);
1097 tcc_error("cannot relocate");
1098 gen_le16(ops
[0].e
.v
);
1102 for(i
= 0;i
< nb_ops
; i
++) {
1104 if (v
& (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
| OP_IM8S
| OP_ADDR
)) {
1105 /* if multiple sizes are given it means we must look
1107 if ((v
| OP_IM8
| OP_IM64
) == (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
)) {
1112 else if (s
== 2 || (v
& OP_IM64
) == 0)
1118 if ((v
& (OP_IM8
| OP_IM8S
| OP_IM16
)) && ops
[i
].e
.sym
)
1119 tcc_error("cannot relocate");
1121 if (v
& (OP_IM8
| OP_IM8S
)) {
1123 } else if (v
& OP_IM16
) {
1124 gen_le16(ops
[i
].e
.v
);
1125 #ifdef TCC_TARGET_X86_64
1126 } else if (v
& OP_IM64
) {
1127 gen_expr64(&ops
[i
].e
);
1129 } else if (pa
->op_type
[i
] == OPT_DISP
|| pa
->op_type
[i
] == OPT_DISP8
) {
1130 gen_disp32(&ops
[i
].e
);
1132 gen_expr32(&ops
[i
].e
);
1137 /* after immediate operands, adjust pc-relative address */
1139 add32le(cur_text_section
->data
+ pc
- 4, pc
- ind
);
1142 /* return the constraint priority (we allocate first the lowest
1143 numbered constraints) */
1144 static inline int constraint_priority(const char *str
)
1146 int priority
, c
, pr
;
1148 /* we take the lowest priority */
1185 tcc_error("unknown constraint '%c'", c
);
1194 static const char *skip_constraint_modifiers(const char *p
)
1196 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1201 /* If T (a token) is of the form "%reg" returns the register
1202 number and type, otherwise return -1. */
1203 ST_FUNC
int asm_parse_regvar (int t
)
1207 if (t
< TOK_IDENT
|| (t
& SYM_FIELD
))
1209 s
= table_ident
[t
- TOK_IDENT
]->str
;
1212 t
= tok_alloc_const(s
+ 1);
1215 parse_operand(tcc_state
, &op
);
1216 /* Accept only integer regs for now. */
1217 if (op
.type
& OP_REG
)
1223 #define REG_OUT_MASK 0x01
1224 #define REG_IN_MASK 0x02
1226 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1228 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1229 int nb_operands
, int nb_outputs
,
1230 const uint8_t *clobber_regs
,
1234 int sorted_op
[MAX_ASM_OPERANDS
];
1235 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1237 uint8_t regs_allocated
[NB_ASM_REGS
];
1240 for(i
=0;i
<nb_operands
;i
++) {
1242 op
->input_index
= -1;
1248 /* compute constraint priority and evaluate references to output
1249 constraints if input constraints */
1250 for(i
=0;i
<nb_operands
;i
++) {
1252 str
= op
->constraint
;
1253 str
= skip_constraint_modifiers(str
);
1254 if (isnum(*str
) || *str
== '[') {
1255 /* this is a reference to another constraint */
1256 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1257 if ((unsigned)k
>= i
|| i
< nb_outputs
)
1258 tcc_error("invalid reference in constraint %d ('%s')",
1261 if (operands
[k
].input_index
>= 0)
1262 tcc_error("cannot reference twice the same operand");
1263 operands
[k
].input_index
= i
;
1265 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1267 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1271 op
->priority
= constraint_priority(str
);
1275 /* sort operands according to their priority */
1276 for(i
=0;i
<nb_operands
;i
++)
1278 for(i
=0;i
<nb_operands
- 1;i
++) {
1279 for(j
=i
+1;j
<nb_operands
;j
++) {
1280 p1
= operands
[sorted_op
[i
]].priority
;
1281 p2
= operands
[sorted_op
[j
]].priority
;
1284 sorted_op
[i
] = sorted_op
[j
];
1290 for(i
= 0;i
< NB_ASM_REGS
; i
++) {
1291 if (clobber_regs
[i
])
1292 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1294 regs_allocated
[i
] = 0;
1296 /* esp cannot be used */
1297 regs_allocated
[4] = REG_IN_MASK
| REG_OUT_MASK
;
1298 /* ebp cannot be used yet */
1299 regs_allocated
[5] = REG_IN_MASK
| REG_OUT_MASK
;
1301 /* allocate registers and generate corresponding asm moves */
1302 for(i
=0;i
<nb_operands
;i
++) {
1305 str
= op
->constraint
;
1306 /* no need to allocate references */
1307 if (op
->ref_index
>= 0)
1309 /* select if register is used for output, input or both */
1310 if (op
->input_index
>= 0) {
1311 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1312 } else if (j
< nb_outputs
) {
1313 reg_mask
= REG_OUT_MASK
;
1315 reg_mask
= REG_IN_MASK
;
1318 if (is_reg_allocated(op
->reg
))
1319 tcc_error("asm regvar requests register that's taken already");
1332 if (j
>= nb_outputs
)
1333 tcc_error("'%c' modifier can only be applied to outputs", c
);
1334 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1337 /* allocate both eax and edx */
1338 if (is_reg_allocated(TREG_XAX
) ||
1339 is_reg_allocated(TREG_XDX
))
1343 regs_allocated
[TREG_XAX
] |= reg_mask
;
1344 regs_allocated
[TREG_XDX
] |= reg_mask
;
1364 if (is_reg_allocated(reg
))
1368 /* eax, ebx, ecx or edx */
1369 for(reg
= 0; reg
< 4; reg
++) {
1370 if (!is_reg_allocated(reg
))
1376 case 'p': /* A general address, for x86(64) any register is acceptable*/
1377 /* any general register */
1378 for(reg
= 0; reg
< 8; reg
++) {
1379 if (!is_reg_allocated(reg
))
1384 /* now we can reload in the register */
1387 regs_allocated
[reg
] |= reg_mask
;
1391 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1397 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
))
1402 /* nothing special to do because the operand is already in
1403 memory, except if the pointer itself is stored in a
1404 memory variable (VT_LLOCAL case) */
1405 /* XXX: fix constant case */
1406 /* if it is a reference to a memory zone, it must lie
1407 in a register, so we reserve the register in the
1408 input registers and a load will be generated
1410 if (j
< nb_outputs
|| c
== 'm') {
1411 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1412 /* any general register */
1413 for(reg
= 0; reg
< 8; reg
++) {
1414 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1419 /* now we can reload in the register */
1420 regs_allocated
[reg
] |= REG_IN_MASK
;
1427 tcc_error("asm constraint %d ('%s') could not be satisfied",
1431 /* if a reference is present for that operand, we assign it too */
1432 if (op
->input_index
>= 0) {
1433 operands
[op
->input_index
].reg
= op
->reg
;
1434 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1438 /* compute out_reg. It is used to store outputs registers to memory
1439 locations references by pointers (VT_LLOCAL case) */
1441 for(i
=0;i
<nb_operands
;i
++) {
1444 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1446 for(reg
= 0; reg
< 8; reg
++) {
1447 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1450 tcc_error("could not find free output register for reloading");
1457 /* print sorted constraints */
1459 for(i
=0;i
<nb_operands
;i
++) {
1462 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1464 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1470 printf("out_reg=%d\n", *pout_reg
);
1474 ST_FUNC
void subst_asm_operand(CString
*add_str
,
1475 SValue
*sv
, int modifier
)
1477 int r
, reg
, size
, val
;
1481 if ((r
& VT_VALMASK
) == VT_CONST
) {
1482 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1484 cstr_ccat(add_str
, '$');
1486 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1487 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1488 /* In case of anonymous symbols ("L.42", used
1489 for static data labels) we can't find them
1490 in the C symbol table when later looking up
1491 this name. So enter them now into the asm label
1492 list when we still know the symbol. */
1493 get_asm_sym(tok_alloc_const(name
), sv
->sym
);
1495 if (tcc_state
->leading_underscore
)
1496 cstr_ccat(add_str
, '_');
1497 cstr_cat(add_str
, name
, -1);
1498 if ((uint32_t)sv
->c
.i
== 0)
1500 cstr_ccat(add_str
, '+');
1503 if (modifier
== 'n')
1505 snprintf(buf
, sizeof(buf
), "%d", (int)sv
->c
.i
);
1506 cstr_cat(add_str
, buf
, -1);
1508 #ifdef TCC_TARGET_X86_64
1510 cstr_cat(add_str
, "(%rip)", -1);
1512 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1513 #ifdef TCC_TARGET_X86_64
1514 snprintf(buf
, sizeof(buf
), "%d(%%rbp)", (int)sv
->c
.i
);
1516 snprintf(buf
, sizeof(buf
), "%d(%%ebp)", (int)sv
->c
.i
);
1518 cstr_cat(add_str
, buf
, -1);
1519 } else if (r
& VT_LVAL
) {
1520 reg
= r
& VT_VALMASK
;
1521 if (reg
>= VT_CONST
)
1522 tcc_internal_error("");
1523 snprintf(buf
, sizeof(buf
), "(%%%s)",
1524 #ifdef TCC_TARGET_X86_64
1525 get_tok_str(TOK_ASM_rax
+ reg
, NULL
)
1527 get_tok_str(TOK_ASM_eax
+ reg
, NULL
)
1530 cstr_cat(add_str
, buf
, -1);
1533 reg
= r
& VT_VALMASK
;
1534 if (reg
>= VT_CONST
)
1535 tcc_internal_error("");
1537 /* choose register operand size */
1538 if ((sv
->type
.t
& VT_BTYPE
) == VT_BYTE
||
1539 (sv
->type
.t
& VT_BTYPE
) == VT_BOOL
)
1541 else if ((sv
->type
.t
& VT_BTYPE
) == VT_SHORT
)
1543 #ifdef TCC_TARGET_X86_64
1544 else if ((sv
->type
.t
& VT_BTYPE
) == VT_LLONG
||
1545 (sv
->type
.t
& VT_BTYPE
) == VT_PTR
)
1550 if (size
== 1 && reg
>= 4)
1553 if (modifier
== 'b') {
1555 tcc_error("cannot use byte register");
1557 } else if (modifier
== 'h') {
1559 tcc_error("cannot use byte register");
1561 } else if (modifier
== 'w') {
1563 } else if (modifier
== 'k') {
1565 #ifdef TCC_TARGET_X86_64
1566 } else if (modifier
== 'q') {
1573 reg
= TOK_ASM_ah
+ reg
;
1576 reg
= TOK_ASM_al
+ reg
;
1579 reg
= TOK_ASM_ax
+ reg
;
1582 reg
= TOK_ASM_eax
+ reg
;
1584 #ifdef TCC_TARGET_X86_64
1586 reg
= TOK_ASM_rax
+ reg
;
1590 snprintf(buf
, sizeof(buf
), "%%%s", get_tok_str(reg
, NULL
));
1591 cstr_cat(add_str
, buf
, -1);
1595 /* generate prolog and epilog code for asm statement */
1596 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1597 int nb_outputs
, int is_output
,
1598 uint8_t *clobber_regs
,
1601 uint8_t regs_allocated
[NB_ASM_REGS
];
1605 /* Strictly speaking %Xbp and %Xsp should be included in the
1606 call-preserved registers, but currently it doesn't matter. */
1607 #ifdef TCC_TARGET_X86_64
1608 #ifdef TCC_TARGET_PE
1609 static const uint8_t reg_saved
[] = { 3, 6, 7, 12, 13, 14, 15 };
1611 static const uint8_t reg_saved
[] = { 3, 12, 13, 14, 15 };
1614 static const uint8_t reg_saved
[] = { 3, 6, 7 };
1617 /* mark all used registers */
1618 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1619 for(i
= 0; i
< nb_operands
;i
++) {
1622 regs_allocated
[op
->reg
] = 1;
1625 /* generate reg save code */
1626 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1628 if (regs_allocated
[reg
]) {
1635 /* generate load code */
1636 for(i
= 0; i
< nb_operands
; i
++) {
1639 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1641 /* memory reference case (for both input and
1645 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1648 } else if (i
>= nb_outputs
|| op
->is_rw
) {
1649 /* load value in register */
1650 load(op
->reg
, op
->vt
);
1655 load(TREG_XDX
, &sv
);
1661 /* generate save code */
1662 for(i
= 0 ; i
< nb_outputs
; i
++) {
1665 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1666 if (!op
->is_memory
) {
1669 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1674 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1675 store(op
->reg
, &sv
);
1678 store(op
->reg
, op
->vt
);
1683 store(TREG_XDX
, &sv
);
1688 /* generate reg restore code */
1689 for(i
= sizeof(reg_saved
)/sizeof(reg_saved
[0]) - 1; i
>= 0; i
--) {
1691 if (regs_allocated
[reg
]) {
1700 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1703 #ifdef TCC_TARGET_X86_64
1707 if (!strcmp(str
, "memory") ||
1708 !strcmp(str
, "cc") ||
1709 !strcmp(str
, "flags"))
1711 reg
= tok_alloc_const(str
);
1712 if (reg
>= TOK_ASM_eax
&& reg
<= TOK_ASM_edi
) {
1714 } else if (reg
>= TOK_ASM_ax
&& reg
<= TOK_ASM_di
) {
1716 #ifdef TCC_TARGET_X86_64
1717 } else if (reg
>= TOK_ASM_rax
&& reg
<= TOK_ASM_rdi
) {
1719 } else if ((reg
= asm_parse_numeric_reg(reg
, &type
)) >= 0) {
1723 tcc_error("invalid clobber register '%s'", str
);
1725 clobber_regs
[reg
] = 1;