Rev 647 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 647 | Rev 6429 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* |
1 | /* |
2 | * i386 specific functions for TCC assembler |
2 | * i386 specific functions for TCC assembler |
3 | * |
3 | * |
4 | * Copyright (c) 2001, 2002 Fabrice Bellard |
4 | * Copyright (c) 2001, 2002 Fabrice Bellard |
- | 5 | * Copyright (c) 2009 Frédéric Feret (x86_64 support) |
|
5 | * |
6 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * version 2 of the License, or (at your option) any later version. |
Line 16... | Line 17... | ||
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
18 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | */ |
Line -... | Line 21... | ||
- | 21 | ||
- | 22 | #include "tcc.h" |
|
- | 23 | ||
20 | 24 | /* #define NB_ASM_REGS 8 */ |
|
- | 25 | #define MAX_OPERANDS 3 |
|
- | 26 | #define NB_SAVED_REGS 3 |
|
- | 27 | ||
- | 28 | #define TOK_ASM_first TOK_ASM_clc |
|
- | 29 | #define TOK_ASM_last TOK_ASM_emms |
|
Line 21... | Line -... | ||
21 | #define MAX_OPERANDS 3 |
- | |
22 | - | ||
23 | typedef struct ASMInstr { |
- | |
24 | uint16_t sym; |
- | |
25 | uint16_t opcode; |
30 | #define TOK_ASM_alllast TOK_ASM_pxor |
26 | uint16_t instr_type; |
31 | |
27 | #define OPC_JMP 0x01 /* jmp operand */ |
32 | #define OPC_JMP 0x01 /* jmp operand */ |
28 | #define OPC_B 0x02 /* only used zith OPC_WL */ |
33 | #define OPC_B 0x02 /* only used with OPC_WL */ |
29 | #define OPC_WL 0x04 /* accepts w, l or no suffix */ |
34 | #define OPC_WL 0x04 /* accepts w, l or no suffix */ |
30 | #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ |
35 | #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ |
31 | #define OPC_REG 0x08 /* register is added to opcode */ |
36 | #define OPC_REG 0x08 /* register is added to opcode */ |
Line 35... | Line 40... | ||
35 | #define OPC_SHIFT 0x80 /* shift opcodes */ |
40 | #define OPC_SHIFT 0x80 /* shift opcodes */ |
36 | #define OPC_D16 0x0100 /* generate data16 prefix */ |
41 | #define OPC_D16 0x0100 /* generate data16 prefix */ |
37 | #define OPC_ARITH 0x0200 /* arithmetic opcodes */ |
42 | #define OPC_ARITH 0x0200 /* arithmetic opcodes */ |
38 | #define OPC_SHORTJMP 0x0400 /* short jmp operand */ |
43 | #define OPC_SHORTJMP 0x0400 /* short jmp operand */ |
39 | #define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */ |
44 | #define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */ |
- | 45 | #ifdef TCC_TARGET_X86_64 |
|
- | 46 | # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ |
|
- | 47 | # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ |
|
- | 48 | # define OPC_WLX OPC_WLQ |
|
- | 49 | #else |
|
- | 50 | # define OPC_WLX OPC_WL |
|
- | 51 | #endif |
|
- | 52 | ||
40 | #define OPC_GROUP_SHIFT 13 |
53 | #define OPC_GROUP_SHIFT 13 |
Line 41... | Line 54... | ||
41 | 54 | ||
42 | /* in order to compress the operand type, we use specific operands and |
55 | /* in order to compress the operand type, we use specific operands and |
- | 56 | we or only with EA */ |
|
43 | we or only with EA */ |
57 | enum { |
44 | #define OPT_REG8 0 /* warning: value is hardcoded from TOK_ASM_xxx */ |
58 | OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ |
45 | #define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */ |
59 | OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ |
- | 60 | OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ |
|
- | 61 | #ifdef TCC_TARGET_X86_64 |
|
- | 62 | OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ |
|
46 | #define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */ |
63 | #endif |
47 | #define OPT_MMX 3 /* warning: value is hardcoded from TOK_ASM_xxx */ |
64 | OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ |
48 | #define OPT_SSE 4 /* warning: value is hardcoded from TOK_ASM_xxx */ |
65 | OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ |
49 | #define OPT_CR 5 /* warning: value is hardcoded from TOK_ASM_xxx */ |
66 | OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ |
50 | #define OPT_TR 6 /* warning: value is hardcoded from TOK_ASM_xxx */ |
67 | OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ |
51 | #define OPT_DB 7 /* warning: value is hardcoded from TOK_ASM_xxx */ |
68 | OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ |
52 | #define OPT_SEG 8 |
69 | OPT_SEG, |
53 | #define OPT_ST 9 |
70 | OPT_ST, |
54 | #define OPT_IM8 10 |
71 | OPT_IM8, |
55 | #define OPT_IM8S 11 |
72 | OPT_IM8S, |
56 | #define OPT_IM16 12 |
73 | OPT_IM16, |
- | 74 | OPT_IM32, |
|
- | 75 | #ifdef TCC_TARGET_X86_64 |
|
- | 76 | OPT_IM64, |
|
57 | #define OPT_IM32 13 |
77 | #endif |
58 | #define OPT_EAX 14 /* %al, %ax or %eax register */ |
78 | OPT_EAX, /* %al, %ax, %eax or %rax register */ |
59 | #define OPT_ST0 15 /* %st(0) register */ |
79 | OPT_ST0, /* %st(0) register */ |
60 | #define OPT_CL 16 /* %cl register */ |
80 | OPT_CL, /* %cl register */ |
61 | #define OPT_DX 17 /* %dx register */ |
81 | OPT_DX, /* %dx register */ |
62 | #define OPT_ADDR 18 /* OP_EA with only offset */ |
82 | OPT_ADDR, /* OP_EA with only offset */ |
63 | #define OPT_INDIR 19 /* *(expr) */ |
- | |
64 | 83 | OPT_INDIR, /* *(expr) */ |
|
65 | /* composite types */ |
84 | /* composite types */ |
66 | #define OPT_COMPOSITE_FIRST 20 |
85 | OPT_COMPOSITE_FIRST, |
67 | #define OPT_IM 20 /* IM8 | IM16 | IM32 */ |
86 | OPT_IM, /* IM8 | IM16 | IM32 | IM64 */ |
68 | #define OPT_REG 21 /* REG8 | REG16 | REG32 */ |
87 | OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ |
- | 88 | OPT_REGW, /* REG16 | REG32 | REG64 */ |
|
- | 89 | OPT_IMW, /* IM16 | IM32 | IM64 */ |
|
69 | #define OPT_REGW 22 /* REG16 | REG32 */ |
90 | #ifdef TCC_TARGET_X86_64 |
70 | #define OPT_IMW 23 /* IM16 | IM32 */ |
91 | OPT_IMNO64, /* IM16 | IM32 */ |
71 | 92 | #endif |
|
72 | /* can be ored with any OPT_xxx */ |
93 | /* can be ored with any OPT_xxx */ |
73 | #define OPT_EA 0x80 |
94 | OPT_EA = 0x80 |
74 | - | ||
75 | uint8_t nb_ops; |
- | |
76 | uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ |
- | |
Line 77... | Line -... | ||
77 | } ASMInstr; |
- | |
78 | - | ||
79 | typedef struct Operand { |
95 | }; |
80 | uint32_t type; |
96 | |
81 | #define OP_REG8 (1 << OPT_REG8) |
97 | #define OP_REG8 (1 << OPT_REG8) |
82 | #define OP_REG16 (1 << OPT_REG16) |
98 | #define OP_REG16 (1 << OPT_REG16) |
83 | #define OP_REG32 (1 << OPT_REG32) |
99 | #define OP_REG32 (1 << OPT_REG32) |
Line 96... | Line 112... | ||
96 | #define OP_ST0 (1 << OPT_ST0) |
112 | #define OP_ST0 (1 << OPT_ST0) |
97 | #define OP_CL (1 << OPT_CL) |
113 | #define OP_CL (1 << OPT_CL) |
98 | #define OP_DX (1 << OPT_DX) |
114 | #define OP_DX (1 << OPT_DX) |
99 | #define OP_ADDR (1 << OPT_ADDR) |
115 | #define OP_ADDR (1 << OPT_ADDR) |
100 | #define OP_INDIR (1 << OPT_INDIR) |
116 | #define OP_INDIR (1 << OPT_INDIR) |
- | 117 | #ifdef TCC_TARGET_X86_64 |
|
- | 118 | # define OP_REG64 (1 << OPT_REG64) |
|
- | 119 | # define OP_IM64 (1 << OPT_IM64) |
|
- | 120 | #else |
|
- | 121 | # define OP_REG64 0 |
|
- | 122 | # define OP_IM64 0 |
|
- | 123 | #endif |
|
Line 101... | Line 124... | ||
101 | 124 | ||
102 | #define OP_EA 0x40000000 |
125 | #define OP_EA 0x40000000 |
- | 126 | #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) |
|
- | 127 | ||
- | 128 | #ifdef TCC_TARGET_X86_64 |
|
- | 129 | # define OP_IM OP_IM64 |
|
- | 130 | # define TREG_XAX TREG_RAX |
|
- | 131 | # define TREG_XCX TREG_RCX |
|
- | 132 | # define TREG_XDX TREG_RDX |
|
103 | #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32) |
133 | #else |
- | 134 | # define OP_IM OP_IM32 |
|
- | 135 | # define TREG_XAX TREG_EAX |
|
- | 136 | # define TREG_XCX TREG_ECX |
|
- | 137 | # define TREG_XDX TREG_EDX |
|
- | 138 | #endif |
|
- | 139 | ||
- | 140 | typedef struct ASMInstr { |
|
- | 141 | uint16_t sym; |
|
- | 142 | uint16_t opcode; |
|
- | 143 | uint16_t instr_type; |
|
- | 144 | uint8_t nb_ops; |
|
- | 145 | uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ |
|
- | 146 | } ASMInstr; |
|
- | 147 | ||
- | 148 | typedef struct Operand { |
|
104 | #define OP_IM OP_IM32 |
149 | uint32_t type; |
105 | int8_t reg; /* register, -1 if none */ |
150 | int8_t reg; /* register, -1 if none */ |
106 | int8_t reg2; /* second register, -1 if none */ |
151 | int8_t reg2; /* second register, -1 if none */ |
107 | uint8_t shift; |
152 | uint8_t shift; |
108 | ExprValue e; |
153 | ExprValue e; |
Line 109... | Line 154... | ||
109 | } Operand; |
154 | } Operand; |
- | 155 | ||
110 | 156 | static const uint8_t reg_to_size[9] = { |
|
111 | static const uint8_t reg_to_size[5] = { |
157 | /* |
112 | [OP_REG8] = 0, |
158 | [OP_REG8] = 0, |
- | 159 | [OP_REG16] = 1, |
|
- | 160 | [OP_REG32] = 2, |
|
- | 161 | #ifdef TCC_TARGET_X86_64 |
|
- | 162 | [OP_REG64] = 3, |
|
- | 163 | #endif |
|
113 | [OP_REG16] = 1, |
164 | */ |
Line 114... | Line -... | ||
114 | [OP_REG32] = 2, |
- | |
115 | }; |
- | |
116 | 165 | 0, 0, 1, 0, 2, 0, 0, 0, 3 |
|
Line 117... | Line 166... | ||
117 | #define WORD_PREFIX_OPCODE 0x66 |
166 | }; |
118 | 167 | ||
119 | #define NB_TEST_OPCODES 30 |
168 | #define NB_TEST_OPCODES 30 |
Line 149... | Line 198... | ||
149 | 0x0e, /* ng */ |
198 | 0x0e, /* ng */ |
150 | 0x0f, /* nle */ |
199 | 0x0f, /* nle */ |
151 | 0x0f, /* g */ |
200 | 0x0f, /* g */ |
152 | }; |
201 | }; |
Line -... | Line 202... | ||
- | 202 | ||
- | 203 | static const uint8_t segment_prefixes[] = { |
|
- | 204 | 0x26, /* es */ |
|
- | 205 | 0x2e, /* cs */ |
|
- | 206 | 0x36, /* ss */ |
|
- | 207 | 0x3e, /* ds */ |
|
- | 208 | 0x64, /* fs */ |
|
- | 209 | 0x65 /* gs */ |
|
- | 210 | }; |
|
153 | 211 | ||
154 | static const ASMInstr asm_instrs[] = { |
212 | static const ASMInstr asm_instrs[] = { |
155 | #define ALT(x) x |
213 | #define ALT(x) x |
156 | #define DEF_ASM_OP0(name, opcode) |
214 | #define DEF_ASM_OP0(name, opcode) |
157 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 }, |
215 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 }, |
158 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }}, |
216 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }}, |
159 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }}, |
217 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }}, |
- | 218 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }}, |
|
- | 219 | #ifdef TCC_TARGET_X86_64 |
|
- | 220 | # include "x86_64-asm.h" |
|
160 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }}, |
221 | #else |
161 | #include "i386-asm.h" |
222 | # include "i386-asm.h" |
162 | 223 | #endif |
|
163 | /* last operation */ |
224 | /* last operation */ |
164 | { 0, }, |
225 | { 0, }, |
Line 165... | Line 226... | ||
165 | }; |
226 | }; |
Line 169... | Line 230... | ||
169 | #define DEF_ASM_OP0(x, opcode) opcode, |
230 | #define DEF_ASM_OP0(x, opcode) opcode, |
170 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) |
231 | #define DEF_ASM_OP0L(name, opcode, group, instr_type) |
171 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) |
232 | #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) |
172 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) |
233 | #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) |
173 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) |
234 | #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) |
- | 235 | #ifdef TCC_TARGET_X86_64 |
|
- | 236 | # include "x86_64-asm.h" |
|
- | 237 | #else |
|
174 | #include "i386-asm.h" |
238 | # include "i386-asm.h" |
- | 239 | #endif |
|
175 | }; |
240 | }; |
Line 176... | Line 241... | ||
176 | 241 | ||
177 | static inline int get_reg_shift(TCCState *s1) |
242 | static inline int get_reg_shift(TCCState *s1) |
178 | { |
243 | { |
- | 244 | int shift, v; |
|
- | 245 | #ifdef I386_ASM_16 |
|
- | 246 | if (s1->seg_size == 16) |
|
179 | int shift, v; |
247 | tcc_error("invalid effective address"); |
180 | 248 | #endif |
|
181 | v = asm_int_expr(s1); |
249 | v = asm_int_expr(s1); |
182 | switch(v) { |
250 | switch(v) { |
183 | case 1: |
251 | case 1: |
184 | shift = 0; |
252 | shift = 0; |
Line 200... | Line 268... | ||
200 | return shift; |
268 | return shift; |
201 | } |
269 | } |
Line 202... | Line 270... | ||
202 | 270 | ||
203 | static int asm_parse_reg(void) |
271 | static int asm_parse_reg(void) |
204 | { |
272 | { |
205 | int reg; |
273 | int reg = 0; |
206 | if (tok != '%') |
274 | if (tok != '%') |
207 | goto error_32; |
275 | goto error_32; |
208 | next(); |
276 | next(); |
209 | if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { |
277 | if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { |
- | 278 | reg = tok - TOK_ASM_eax; |
|
- | 279 | #ifdef TCC_TARGET_X86_64 |
|
210 | reg = tok - TOK_ASM_eax; |
280 | } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { |
- | 281 | reg = tok - TOK_ASM_rax; |
|
- | 282 | #endif |
|
- | 283 | #ifdef I386_ASM_16 |
|
211 | next(); |
284 | } else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) { |
- | 285 | reg = tok - TOK_ASM_ax; |
|
212 | return reg; |
286 | #endif |
213 | } else { |
287 | } else { |
214 | error_32: |
288 | error_32: |
215 | expect("32 bit register"); |
- | |
216 | return 0; |
289 | expect("register"); |
- | 290 | } |
|
- | 291 | next(); |
|
217 | } |
292 | return reg; |
Line 218... | Line 293... | ||
218 | } |
293 | } |
219 | 294 | ||
220 | static void parse_operand(TCCState *s1, Operand *op) |
295 | static void parse_operand(TCCState *s1, Operand *op) |
Line 233... | Line 308... | ||
233 | next(); |
308 | next(); |
234 | if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { |
309 | if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { |
235 | reg = tok - TOK_ASM_al; |
310 | reg = tok - TOK_ASM_al; |
236 | op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ |
311 | op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ |
237 | op->reg = reg & 7; |
312 | op->reg = reg & 7; |
238 | if ((op->type & OP_REG) && op->reg == TREG_EAX) |
313 | if ((op->type & OP_REG) && op->reg == TREG_XAX) |
239 | op->type |= OP_EAX; |
314 | op->type |= OP_EAX; |
240 | else if (op->type == OP_REG8 && op->reg == TREG_ECX) |
315 | else if (op->type == OP_REG8 && op->reg == TREG_XCX) |
241 | op->type |= OP_CL; |
316 | op->type |= OP_CL; |
242 | else if (op->type == OP_REG16 && op->reg == TREG_EDX) |
317 | else if (op->type == OP_REG16 && op->reg == TREG_XDX) |
243 | op->type |= OP_DX; |
318 | op->type |= OP_DX; |
244 | } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { |
319 | } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { |
245 | op->type = OP_DB; |
320 | op->type = OP_DB; |
246 | op->reg = tok - TOK_ASM_dr0; |
321 | op->reg = tok - TOK_ASM_dr0; |
247 | } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { |
322 | } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { |
Line 253... | Line 328... | ||
253 | next(); |
328 | next(); |
254 | if (tok == '(') { |
329 | if (tok == '(') { |
255 | next(); |
330 | next(); |
256 | if (tok != TOK_PPNUM) |
331 | if (tok != TOK_PPNUM) |
257 | goto reg_error; |
332 | goto reg_error; |
258 | p = tokc.cstr->data; |
333 | p = tokc.str.data; |
259 | reg = p[0] - '0'; |
334 | reg = p[0] - '0'; |
260 | if ((unsigned)reg >= 8 || p[1] != '\0') |
335 | if ((unsigned)reg >= 8 || p[1] != '\0') |
261 | goto reg_error; |
336 | goto reg_error; |
262 | op->reg = reg; |
337 | op->reg = reg; |
263 | next(); |
338 | next(); |
Line 266... | Line 341... | ||
266 | if (op->reg == 0) |
341 | if (op->reg == 0) |
267 | op->type |= OP_ST0; |
342 | op->type |= OP_ST0; |
268 | goto no_skip; |
343 | goto no_skip; |
269 | } else { |
344 | } else { |
270 | reg_error: |
345 | reg_error: |
271 | error("unknown register"); |
346 | tcc_error("unknown register"); |
272 | } |
347 | } |
273 | next(); |
348 | next(); |
274 | no_skip: ; |
349 | no_skip: ; |
275 | } else if (tok == '$') { |
350 | } else if (tok == '$') { |
276 | /* constant value */ |
351 | /* constant value */ |
277 | next(); |
352 | next(); |
278 | asm_expr(s1, &e); |
353 | asm_expr(s1, &e); |
279 | op->type = OP_IM32; |
354 | op->type = OP_IM; |
280 | op->e.v = e.v; |
355 | op->e.v = e.v; |
281 | op->e.sym = e.sym; |
356 | op->e.sym = e.sym; |
282 | if (!op->e.sym) { |
357 | if (!op->e.sym) { |
283 | if (op->e.v == (uint8_t)op->e.v) |
358 | if (op->e.v == (uint8_t)op->e.v) |
284 | op->type |= OP_IM8; |
359 | op->type |= OP_IM8; |
285 | if (op->e.v == (int8_t)op->e.v) |
360 | if (op->e.v == (int8_t)op->e.v) |
286 | op->type |= OP_IM8S; |
361 | op->type |= OP_IM8S; |
287 | if (op->e.v == (uint16_t)op->e.v) |
362 | if (op->e.v == (uint16_t)op->e.v) |
288 | op->type |= OP_IM16; |
363 | op->type |= OP_IM16; |
- | 364 | #ifdef TCC_TARGET_X86_64 |
|
- | 365 | if (op->e.v == (uint32_t)op->e.v) |
|
- | 366 | op->type |= OP_IM32; |
|
- | 367 | #endif |
|
289 | } |
368 | } |
290 | } else { |
369 | } else { |
291 | /* address(reg,reg2,shift) with all variants */ |
370 | /* address(reg,reg2,shift) with all variants */ |
292 | op->type = OP_EA; |
371 | op->type = OP_EA; |
293 | op->reg = -1; |
372 | op->reg = -1; |
Line 296... | Line 375... | ||
296 | if (tok != '(') { |
375 | if (tok != '(') { |
297 | asm_expr(s1, &e); |
376 | asm_expr(s1, &e); |
298 | op->e.v = e.v; |
377 | op->e.v = e.v; |
299 | op->e.sym = e.sym; |
378 | op->e.sym = e.sym; |
300 | } else { |
379 | } else { |
- | 380 | next(); |
|
- | 381 | if (tok == '%') { |
|
- | 382 | unget_tok('('); |
|
301 | op->e.v = 0; |
383 | op->e.v = 0; |
302 | op->e.sym = NULL; |
384 | op->e.sym = NULL; |
- | 385 | } else { |
|
- | 386 | /* bracketed offset expression */ |
|
- | 387 | asm_expr(s1, &e); |
|
- | 388 | if (tok != ')') |
|
- | 389 | expect(")"); |
|
- | 390 | next(); |
|
- | 391 | op->e.v = e.v; |
|
- | 392 | op->e.sym = e.sym; |
|
- | 393 | } |
|
303 | } |
394 | } |
304 | if (tok == '(') { |
395 | if (tok == '(') { |
305 | next(); |
396 | next(); |
306 | if (tok != ',') { |
397 | if (tok != ',') { |
307 | op->reg = asm_parse_reg(); |
398 | op->reg = asm_parse_reg(); |
Line 309... | Line 400... | ||
309 | if (tok == ',') { |
400 | if (tok == ',') { |
310 | next(); |
401 | next(); |
311 | if (tok != ',') { |
402 | if (tok != ',') { |
312 | op->reg2 = asm_parse_reg(); |
403 | op->reg2 = asm_parse_reg(); |
313 | } |
404 | } |
- | 405 | if (tok == ',') { |
|
314 | skip(','); |
406 | next(); |
315 | op->shift = get_reg_shift(s1); |
407 | op->shift = get_reg_shift(s1); |
316 | } |
408 | } |
- | 409 | } |
|
317 | skip(')'); |
410 | skip(')'); |
318 | } |
411 | } |
319 | if (op->reg == -1 && op->reg2 == -1) |
412 | if (op->reg == -1 && op->reg2 == -1) |
320 | op->type |= OP_ADDR; |
413 | op->type |= OP_ADDR; |
321 | } |
414 | } |
322 | op->type |= indir; |
415 | op->type |= indir; |
323 | } |
416 | } |
Line 324... | Line 417... | ||
324 | 417 | ||
325 | /* XXX: unify with C code output ? */ |
418 | /* XXX: unify with C code output ? */ |
326 | static void gen_expr32(ExprValue *pe) |
419 | ST_FUNC void gen_expr32(ExprValue *pe) |
- | 420 | { |
|
- | 421 | gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); |
|
- | 422 | } |
|
327 | { |
423 | |
328 | if (pe->sym) |
424 | #ifdef TCC_TARGET_X86_64 |
- | 425 | static void gen_expr64(ExprValue *pe) |
|
329 | greloc(cur_text_section, pe->sym, ind, R_386_32); |
426 | { |
330 | gen_le32(pe->v); |
427 | gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); |
- | 428 | } |
|
Line 331... | Line 429... | ||
331 | } |
429 | #endif |
332 | 430 | ||
333 | /* XXX: unify with C code output ? */ |
431 | /* XXX: unify with C code output ? */ |
- | 432 | static void gen_disp32(ExprValue *pe) |
|
- | 433 | { |
|
- | 434 | Sym *sym = pe->sym; |
|
- | 435 | if (sym && sym->r == cur_text_section->sh_num) { |
|
- | 436 | /* same section: we can output an absolute value. Note |
|
- | 437 | that the TCC compiler behaves differently here because |
|
- | 438 | it always outputs a relocation to ease (future) code |
|
- | 439 | elimination in the linker */ |
|
- | 440 | gen_le32(pe->v + sym->jnext - ind - 4); |
|
- | 441 | } else { |
|
- | 442 | if (sym && sym->type.t == VT_VOID) { |
|
- | 443 | sym->type.t = VT_FUNC; |
|
- | 444 | sym->type.ref = NULL; |
|
- | 445 | } |
|
- | 446 | gen_addrpc32(VT_SYM, sym, pe->v); |
|
- | 447 | } |
|
- | 448 | } |
|
- | 449 | ||
- | 450 | #ifdef I386_ASM_16 |
|
- | 451 | static void gen_expr16(ExprValue *pe) |
|
- | 452 | { |
|
- | 453 | if (pe->sym) |
|
- | 454 | greloc(cur_text_section, pe->sym, ind, R_386_16); |
|
- | 455 | gen_le16(pe->v); |
|
- | 456 | } |
|
334 | static void gen_disp32(ExprValue *pe) |
457 | static void gen_disp16(ExprValue *pe) |
335 | { |
458 | { |
336 | Sym *sym; |
459 | Sym *sym; |
337 | sym = pe->sym; |
460 | sym = pe->sym; |
338 | if (sym) { |
461 | if (sym) { |
339 | if (sym->r == cur_text_section->sh_num) { |
462 | if (sym->r == cur_text_section->sh_num) { |
340 | /* same section: we can output an absolute value. Note |
463 | /* same section: we can output an absolute value. Note |
341 | that the TCC compiler behaves differently here because |
464 | that the TCC compiler behaves differently here because |
342 | it always outputs a relocation to ease (future) code |
465 | it always outputs a relocation to ease (future) code |
343 | elimination in the linker */ |
466 | elimination in the linker */ |
344 | gen_le32(pe->v + (long)sym->next - ind - 4); |
467 | gen_le16(pe->v + sym->jnext - ind - 2); |
345 | } else { |
468 | } else { |
346 | greloc(cur_text_section, sym, ind, R_386_PC32); |
469 | greloc(cur_text_section, sym, ind, R_386_PC16); |
347 | gen_le32(pe->v - 4); |
470 | gen_le16(pe->v - 2); |
348 | } |
471 | } |
349 | } else { |
472 | } else { |
350 | /* put an empty PC32 relocation */ |
473 | /* put an empty PC32 relocation */ |
351 | put_elf_reloc(symtab_section, cur_text_section, |
474 | put_elf_reloc(symtab_section, cur_text_section, |
352 | ind, R_386_PC32, 0); |
475 | ind, R_386_PC16, 0); |
353 | gen_le32(pe->v - 4); |
476 | gen_le16(pe->v - 2); |
354 | } |
- | |
355 | } |
- | |
356 | - | ||
357 | - | ||
358 | static void gen_le16(int v) |
477 | } |
359 | { |
- | |
360 | g(v); |
- | |
Line 361... | Line 478... | ||
361 | g(v >> 8); |
478 | } |
362 | } |
479 | #endif |
363 | 480 | ||
364 | /* generate the modrm operand */ |
481 | /* generate the modrm operand */ |
Line 365... | Line 482... | ||
365 | static inline void asm_modrm(int reg, Operand *op) |
482 | static inline void asm_modrm(int reg, Operand *op) |
366 | { |
483 | { |
367 | int mod, reg1, reg2, sib_reg1; |
484 | int mod, reg1, reg2, sib_reg1; |
368 | 485 | ||
- | 486 | if (op->type & (OP_REG | OP_MMX | OP_SSE)) { |
|
- | 487 | g(0xc0 + (reg << 3) + op->reg); |
|
- | 488 | } else if (op->reg == -1 && op->reg2 == -1) { |
|
- | 489 | /* displacement only */ |
|
- | 490 | #ifdef I386_ASM_16 |
|
- | 491 | if (tcc_state->seg_size == 16) { |
|
- | 492 | g(0x06 + (reg << 3)); |
|
369 | if (op->type & (OP_REG | OP_MMX | OP_SSE)) { |
493 | gen_expr16(&op->e); |
370 | g(0xc0 + (reg << 3) + op->reg); |
494 | } else if (tcc_state->seg_size == 32) |
- | 495 | #endif |
|
371 | } else if (op->reg == -1 && op->reg2 == -1) { |
496 | { |
372 | /* displacement only */ |
497 | g(0x05 + (reg << 3)); |
373 | g(0x05 + (reg << 3)); |
498 | gen_expr32(&op->e); |
374 | gen_expr32(&op->e); |
499 | } |
375 | } else { |
500 | } else { |
Line 387... | Line 512... | ||
387 | } |
512 | } |
388 | /* compute if sib byte needed */ |
513 | /* compute if sib byte needed */ |
389 | reg1 = op->reg; |
514 | reg1 = op->reg; |
390 | if (op->reg2 != -1) |
515 | if (op->reg2 != -1) |
391 | reg1 = 4; |
516 | reg1 = 4; |
- | 517 | #ifdef I386_ASM_16 |
|
- | 518 | if (tcc_state->seg_size == 32) { |
|
- | 519 | #endif |
|
392 | g(mod + (reg << 3) + reg1); |
520 | g(mod + (reg << 3) + reg1); |
393 | if (reg1 == 4) { |
521 | if (reg1 == 4) { |
394 | /* add sib byte */ |
522 | /* add sib byte */ |
395 | reg2 = op->reg2; |
523 | reg2 = op->reg2; |
396 | if (reg2 == -1) |
524 | if (reg2 == -1) |
397 | reg2 = 4; /* indicate no index */ |
525 | reg2 = 4; /* indicate no index */ |
398 | g((op->shift << 6) + (reg2 << 3) + sib_reg1); |
526 | g((op->shift << 6) + (reg2 << 3) + sib_reg1); |
399 | } |
527 | } |
- | 528 | #ifdef I386_ASM_16 |
|
- | 529 | } else if (tcc_state->seg_size == 16) { |
|
- | 530 | /* edi = 7, esi = 6 --> di = 5, si = 4 */ |
|
- | 531 | if ((reg1 == 6) || (reg1 == 7)) { |
|
- | 532 | reg1 -= 2; |
|
- | 533 | /* ebx = 3 --> bx = 7 */ |
|
- | 534 | } else if (reg1 == 3) { |
|
- | 535 | reg1 = 7; |
|
- | 536 | /* o32 = 5 --> o16 = 6 */ |
|
- | 537 | } else if (reg1 == 5) { |
|
- | 538 | reg1 = 6; |
|
- | 539 | /* sib not valid in 16-bit mode */ |
|
- | 540 | } else if (reg1 == 4) { |
|
- | 541 | reg2 = op->reg2; |
|
- | 542 | /* bp + si + offset */ |
|
- | 543 | if ((sib_reg1 == 5) && (reg2 == 6)) { |
|
- | 544 | reg1 = 2; |
|
- | 545 | /* bp + di + offset */ |
|
- | 546 | } else if ((sib_reg1 == 5) && (reg2 == 7)) { |
|
- | 547 | reg1 = 3; |
|
- | 548 | /* bx + si + offset */ |
|
- | 549 | } else if ((sib_reg1 == 3) && (reg2 == 6)) { |
|
- | 550 | reg1 = 0; |
|
- | 551 | /* bx + di + offset */ |
|
- | 552 | } else if ((sib_reg1 == 3) && (reg2 == 7)) { |
|
- | 553 | reg1 = 1; |
|
- | 554 | } else { |
|
- | 555 | tcc_error("invalid effective address"); |
|
400 | 556 | } |
|
- | 557 | if (op->e.v == 0) |
|
- | 558 | mod = 0; |
|
- | 559 | } else { |
|
- | 560 | tcc_error("invalid register"); |
|
- | 561 | } |
|
- | 562 | g(mod + (reg << 3) + reg1); |
|
- | 563 | } |
|
- | 564 | #endif |
|
401 | /* add offset */ |
565 | /* add offset */ |
402 | if (mod == 0x40) { |
566 | if (mod == 0x40) { |
403 | g(op->e.v); |
567 | g(op->e.v); |
404 | } else if (mod == 0x80 || op->reg == -1) { |
568 | } else if (mod == 0x80 || op->reg == -1) { |
- | 569 | #ifdef I386_ASM_16 |
|
- | 570 | if (tcc_state->seg_size == 16) |
|
- | 571 | gen_expr16(&op->e); |
|
- | 572 | else if (tcc_state->seg_size == 32) |
|
- | 573 | #endif |
|
405 | gen_expr32(&op->e); |
574 | gen_expr32(&op->e); |
406 | } |
575 | } |
407 | } |
576 | } |
408 | } |
577 | } |
Line 409... | Line 578... | ||
409 | 578 | ||
410 | static void asm_opcode(TCCState *s1, int opcode) |
579 | ST_FUNC void asm_opcode(TCCState *s1, int opcode) |
411 | { |
580 | { |
412 | const ASMInstr *pa; |
581 | const ASMInstr *pa; |
413 | int i, modrm_index, reg, v, op1, is_short_jmp; |
582 | int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix; |
414 | int nb_ops, s, ss; |
583 | int nb_ops, s; |
415 | Operand ops[MAX_OPERANDS], *pop; |
584 | Operand ops[MAX_OPERANDS], *pop; |
- | 585 | int op_type[3]; /* decoded op type */ |
|
- | 586 | #ifdef I386_ASM_16 |
|
- | 587 | static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0; |
|
- | 588 | #endif |
|
- | 589 | ||
- | 590 | /* force synthetic ';' after prefix instruction, so we can handle */ |
|
- | 591 | /* one-line things like "rep stosb" instead of only "rep\nstosb" */ |
|
- | 592 | if (opcode >= TOK_ASM_wait && opcode <= TOK_ASM_repnz) |
|
Line 416... | Line 593... | ||
416 | int op_type[3]; /* decoded op type */ |
593 | unget_tok(';'); |
417 | 594 | ||
418 | /* get operands */ |
595 | /* get operands */ |
- | 596 | pop = ops; |
|
419 | pop = ops; |
597 | nb_ops = 0; |
420 | nb_ops = 0; |
598 | seg_prefix = 0; |
421 | for(;;) { |
599 | for(;;) { |
422 | if (tok == ';' || tok == TOK_LINEFEED) |
600 | if (tok == ';' || tok == TOK_LINEFEED) |
423 | break; |
601 | break; |
424 | if (nb_ops >= MAX_OPERANDS) { |
602 | if (nb_ops >= MAX_OPERANDS) { |
425 | error("incorrect number of operands"); |
603 | tcc_error("incorrect number of operands"); |
- | 604 | } |
|
- | 605 | parse_operand(s1, pop); |
|
- | 606 | if (tok == ':') { |
|
- | 607 | if (pop->type != OP_SEG || seg_prefix) |
|
- | 608 | tcc_error("incorrect prefix"); |
|
- | 609 | seg_prefix = segment_prefixes[pop->reg]; |
|
- | 610 | next(); |
|
- | 611 | parse_operand(s1, pop); |
|
- | 612 | #ifndef I386_ASM_16 |
|
- | 613 | if (!(pop->type & OP_EA)) { |
|
- | 614 | tcc_error("segment prefix must be followed by memory reference"); |
|
- | 615 | } |
|
426 | } |
616 | #endif |
427 | parse_operand(s1, pop); |
617 | } |
428 | pop++; |
618 | pop++; |
429 | nb_ops++; |
619 | nb_ops++; |
430 | if (tok != ',') |
620 | if (tok != ',') |
Line 442... | Line 632... | ||
442 | if (pa->instr_type & OPC_FARITH) { |
632 | if (pa->instr_type & OPC_FARITH) { |
443 | v = opcode - pa->sym; |
633 | v = opcode - pa->sym; |
444 | if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) |
634 | if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) |
445 | continue; |
635 | continue; |
446 | } else if (pa->instr_type & OPC_ARITH) { |
636 | } else if (pa->instr_type & OPC_ARITH) { |
447 | if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4)) |
637 | if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) |
448 | continue; |
638 | continue; |
449 | goto compute_size; |
639 | s = (opcode - pa->sym) % NBWLX; |
450 | } else if (pa->instr_type & OPC_SHIFT) { |
640 | } else if (pa->instr_type & OPC_SHIFT) { |
451 | if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4)) |
641 | if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) |
452 | continue; |
642 | continue; |
453 | goto compute_size; |
643 | s = (opcode - pa->sym) % NBWLX; |
454 | } else if (pa->instr_type & OPC_TEST) { |
644 | } else if (pa->instr_type & OPC_TEST) { |
455 | if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) |
645 | if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) |
456 | continue; |
646 | continue; |
457 | } else if (pa->instr_type & OPC_B) { |
647 | } else if (pa->instr_type & OPC_B) { |
458 | if (!(opcode >= pa->sym && opcode <= pa->sym + 3)) |
648 | if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) |
459 | continue; |
649 | continue; |
460 | compute_size: |
- | |
461 | s = (opcode - pa->sym) & 3; |
650 | s = opcode - pa->sym; |
462 | } else if (pa->instr_type & OPC_WL) { |
651 | } else if (pa->instr_type & OPC_WLX) { |
463 | if (!(opcode >= pa->sym && opcode <= pa->sym + 2)) |
652 | if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) |
464 | continue; |
653 | continue; |
465 | s = opcode - pa->sym + 1; |
654 | s = opcode - pa->sym + 1; |
466 | } else { |
655 | } else { |
467 | if (pa->sym != opcode) |
656 | if (pa->sym != opcode) |
468 | continue; |
657 | continue; |
Line 474... | Line 663... | ||
474 | int op1, op2; |
663 | int op1, op2; |
475 | op1 = pa->op_type[i]; |
664 | op1 = pa->op_type[i]; |
476 | op2 = op1 & 0x1f; |
665 | op2 = op1 & 0x1f; |
477 | switch(op2) { |
666 | switch(op2) { |
478 | case OPT_IM: |
667 | case OPT_IM: |
479 | v = OP_IM8 | OP_IM16 | OP_IM32; |
668 | v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64; |
480 | break; |
669 | break; |
481 | case OPT_REG: |
670 | case OPT_REG: |
482 | v = OP_REG8 | OP_REG16 | OP_REG32; |
671 | v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; |
483 | break; |
672 | break; |
484 | case OPT_REGW: |
673 | case OPT_REGW: |
485 | v = OP_REG16 | OP_REG32; |
674 | v = OP_REG16 | OP_REG32 | OP_REG64; |
486 | break; |
675 | break; |
487 | case OPT_IMW: |
676 | case OPT_IMW: |
- | 677 | v = OP_IM16 | OP_IM32 | OP_IM64; |
|
- | 678 | break; |
|
- | 679 | #ifdef TCC_TARGET_X86_64 |
|
- | 680 | case OPT_IMNO64: |
|
488 | v = OP_IM16 | OP_IM32; |
681 | v = OP_IM16 | OP_IM32; |
489 | break; |
682 | break; |
- | 683 | #endif |
|
490 | default: |
684 | default: |
491 | v = 1 << op2; |
685 | v = 1 << op2; |
492 | break; |
686 | break; |
493 | } |
687 | } |
494 | if (op1 & OPT_EA) |
688 | if (op1 & OPT_EA) |
Line 500... | Line 694... | ||
500 | /* all is matching ! */ |
694 | /* all is matching ! */ |
501 | break; |
695 | break; |
502 | next: ; |
696 | next: ; |
503 | } |
697 | } |
504 | if (pa->sym == 0) { |
698 | if (pa->sym == 0) { |
505 | if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) { |
699 | if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { |
506 | int b; |
700 | int b; |
507 | b = op0_codes[opcode - TOK_ASM_pusha]; |
701 | b = op0_codes[opcode - TOK_ASM_first]; |
- | 702 | #ifdef I386_ASM_16 |
|
- | 703 | if (opcode == TOK_ASM_o32) { |
|
- | 704 | if (s1->seg_size == 32) |
|
- | 705 | tcc_error("incorrect prefix"); |
|
- | 706 | else |
|
- | 707 | o32 = data32 = 1; |
|
- | 708 | } else if (opcode == TOK_ASM_a32) { |
|
- | 709 | if (s1->seg_size == 32) |
|
- | 710 | tcc_error("incorrect prefix"); |
|
- | 711 | else |
|
- | 712 | a32 = addr32 = 1; |
|
- | 713 | } |
|
- | 714 | #endif |
|
508 | if (b & 0xff00) |
715 | if (b & 0xff00) |
509 | g(b >> 8); |
716 | g(b >> 8); |
510 | g(b); |
717 | g(b); |
511 | return; |
718 | return; |
- | 719 | } else if (opcode <= TOK_ASM_alllast) { |
|
- | 720 | tcc_error("bad operand with opcode '%s'", |
|
- | 721 | get_tok_str(opcode, NULL)); |
|
512 | } else { |
722 | } else { |
513 | error("unknown opcode '%s'", |
723 | tcc_error("unknown opcode '%s'", |
514 | get_tok_str(opcode, NULL)); |
724 | get_tok_str(opcode, NULL)); |
515 | } |
725 | } |
516 | } |
726 | } |
517 | /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ |
727 | /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ |
518 | if (s == 3) { |
728 | if (s == NBWLX-1) { |
519 | for(i = 0; s == 3 && i < nb_ops; i++) { |
729 | for(i = 0; s == NBWLX-1 && i < nb_ops; i++) { |
520 | if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) |
730 | if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) |
521 | s = reg_to_size[ops[i].type & OP_REG]; |
731 | s = reg_to_size[ops[i].type & OP_REG]; |
522 | } |
732 | } |
523 | if (s == 3) { |
733 | if (s == NBWLX-1) { |
524 | if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && |
734 | if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && |
525 | (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) |
735 | (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64))) |
526 | s = 2; |
736 | s = 2; |
527 | else |
737 | else |
528 | error("cannot infer opcode suffix"); |
738 | tcc_error("cannot infer opcode suffix"); |
- | 739 | } |
|
- | 740 | } |
|
- | 741 | ||
- | 742 | #ifdef I386_ASM_16 |
|
- | 743 | for(i = 0; i < nb_ops; i++) { |
|
- | 744 | if (ops[i].type & OP_REG32) { |
|
- | 745 | if (s1->seg_size == 16) |
|
- | 746 | o32 = 1; |
|
- | 747 | } else if (!(ops[i].type & OP_REG32)) { |
|
- | 748 | if (s1->seg_size == 32) |
|
- | 749 | o32 = 1; |
|
- | 750 | } |
|
- | 751 | } |
|
- | 752 | ||
- | 753 | ||
- | 754 | if (s == 1 || (pa->instr_type & OPC_D16)) { |
|
- | 755 | if (s1->seg_size == 32) |
|
- | 756 | o32 = 1; |
|
- | 757 | } else if (s == 2) { |
|
- | 758 | if (s1->seg_size == 16) { |
|
- | 759 | if (!(pa->instr_type & OPC_D16)) |
|
- | 760 | o32 = 1; |
|
529 | } |
761 | } |
530 | } |
762 | } |
Line -... | Line 763... | ||
- | 763 | ||
- | 764 | /* generate a16/a32 prefix if needed */ |
|
- | 765 | if ((a32 == 1) && (addr32 == 0)) |
|
- | 766 | g(0x67); |
|
- | 767 | /* generate o16/o32 prefix if needed */ |
|
- | 768 | if ((o32 == 1) && (data32 == 0)) |
|
- | 769 | g(0x66); |
|
- | 770 | ||
- | 771 | addr32 = data32 = 0; |
|
531 | 772 | #else |
|
532 | /* generate data16 prefix if needed */ |
- | |
533 | ss = s; |
773 | /* generate data16 prefix if needed */ |
534 | if (s == 1 || (pa->instr_type & OPC_D16)) |
774 | if (s == 1 || (pa->instr_type & OPC_D16)) |
- | 775 | g(0x66); |
|
535 | g(WORD_PREFIX_OPCODE); |
776 | #ifdef TCC_TARGET_X86_64 |
- | 777 | else if (s == 3) { |
|
- | 778 | /* generate REX prefix */ |
|
- | 779 | if ((opcode != TOK_ASM_push && opcode != TOK_ASM_pop) |
|
536 | else if (s == 2) |
780 | || !(ops[0].type & OP_REG64)) |
- | 781 | g(0x48); |
|
- | 782 | } |
|
- | 783 | #endif |
|
- | 784 | #endif |
|
537 | s = 1; |
785 | |
538 | /* now generates the operation */ |
786 | /* now generates the operation */ |
539 | if (pa->instr_type & OPC_FWAIT) |
787 | if (pa->instr_type & OPC_FWAIT) |
- | 788 | g(0x9b); |
|
- | 789 | if (seg_prefix) |
|
Line 540... | Line 790... | ||
540 | g(0x9b); |
790 | g(seg_prefix); |
541 | 791 | ||
542 | v = pa->opcode; |
792 | v = pa->opcode; |
543 | if (v == 0x69 || v == 0x69) { |
793 | if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { |
544 | /* kludge for imul $im, %reg */ |
794 | /* kludge for imul $im, %reg */ |
- | 795 | nb_ops = 3; |
|
545 | nb_ops = 3; |
796 | ops[2] = ops[1]; |
546 | ops[2] = ops[1]; |
797 | op_type[2] = op_type[1]; |
547 | } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { |
798 | } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { |
548 | v--; /* int $3 case */ |
799 | v--; /* int $3 case */ |
549 | nb_ops = 0; |
800 | nb_ops = 0; |
Line 555... | Line 806... | ||
555 | v += ops[0].reg << 3; |
806 | v += ops[0].reg << 3; |
556 | } |
807 | } |
557 | nb_ops = 0; |
808 | nb_ops = 0; |
558 | } else if (v <= 0x05) { |
809 | } else if (v <= 0x05) { |
559 | /* arith case */ |
810 | /* arith case */ |
560 | v += ((opcode - TOK_ASM_addb) >> 2) << 3; |
811 | v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; |
561 | } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) { |
812 | } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) { |
562 | /* fpu arith case */ |
813 | /* fpu arith case */ |
563 | v += ((opcode - pa->sym) / 6) << 3; |
814 | v += ((opcode - pa->sym) / 6) << 3; |
564 | } |
815 | } |
565 | if (pa->instr_type & OPC_REG) { |
816 | if (pa->instr_type & OPC_REG) { |
Line 572... | Line 823... | ||
572 | /* mov $im, %reg case */ |
823 | /* mov $im, %reg case */ |
573 | if (pa->opcode == 0xb0 && s >= 1) |
824 | if (pa->opcode == 0xb0 && s >= 1) |
574 | v += 7; |
825 | v += 7; |
575 | } |
826 | } |
576 | if (pa->instr_type & OPC_B) |
827 | if (pa->instr_type & OPC_B) |
577 | v += s; |
828 | v += s >= 1; |
578 | if (pa->instr_type & OPC_TEST) |
829 | if (pa->instr_type & OPC_TEST) |
579 | v += test_bits[opcode - pa->sym]; |
830 | v += test_bits[opcode - pa->sym]; |
580 | if (pa->instr_type & OPC_SHORTJMP) { |
831 | if (pa->instr_type & OPC_SHORTJMP) { |
581 | Sym *sym; |
832 | Sym *sym; |
582 | int jmp_disp; |
833 | int jmp_disp; |
Line 585... | Line 836... | ||
585 | sym = ops[0].e.sym; |
836 | sym = ops[0].e.sym; |
586 | if (!sym) |
837 | if (!sym) |
587 | goto no_short_jump; |
838 | goto no_short_jump; |
588 | if (sym->r != cur_text_section->sh_num) |
839 | if (sym->r != cur_text_section->sh_num) |
589 | goto no_short_jump; |
840 | goto no_short_jump; |
590 | jmp_disp = ops[0].e.v + (long)sym->next - ind - 2; |
841 | jmp_disp = ops[0].e.v + sym->jnext - ind - 2; |
591 | if (jmp_disp == (int8_t)jmp_disp) { |
842 | if (jmp_disp == (int8_t)jmp_disp) { |
592 | /* OK to generate jump */ |
843 | /* OK to generate jump */ |
593 | is_short_jmp = 1; |
844 | is_short_jmp = 1; |
594 | ops[0].e.v = jmp_disp; |
845 | ops[0].e.v = jmp_disp; |
595 | } else { |
846 | } else { |
Line 600... | Line 851... | ||
600 | if (v == 0xeb) |
851 | if (v == 0xeb) |
601 | v = 0xe9; |
852 | v = 0xe9; |
602 | else |
853 | else |
603 | v += 0x0f10; |
854 | v += 0x0f10; |
604 | } else { |
855 | } else { |
605 | error("invalid displacement"); |
856 | tcc_error("invalid displacement"); |
606 | } |
857 | } |
607 | } |
858 | } |
608 | } |
859 | } |
609 | op1 = v >> 8; |
860 | op1 = v >> 8; |
610 | if (op1) |
861 | if (op1) |
Line 612... | Line 863... | ||
612 | g(v); |
863 | g(v); |
Line 613... | Line 864... | ||
613 | 864 | ||
614 | /* search which operand will used for modrm */ |
865 | /* search which operand will used for modrm */ |
615 | modrm_index = 0; |
866 | modrm_index = 0; |
616 | if (pa->instr_type & OPC_SHIFT) { |
867 | if (pa->instr_type & OPC_SHIFT) { |
617 | reg = (opcode - pa->sym) >> 2; |
868 | reg = (opcode - pa->sym) / NBWLX; |
618 | if (reg == 6) |
869 | if (reg == 6) |
619 | reg = 7; |
870 | reg = 7; |
620 | } else if (pa->instr_type & OPC_ARITH) { |
871 | } else if (pa->instr_type & OPC_ARITH) { |
621 | reg = (opcode - pa->sym) >> 2; |
872 | reg = (opcode - pa->sym) / NBWLX; |
622 | } else if (pa->instr_type & OPC_FARITH) { |
873 | } else if (pa->instr_type & OPC_FARITH) { |
623 | reg = (opcode - pa->sym) / 6; |
874 | reg = (opcode - pa->sym) / 6; |
624 | } else { |
875 | } else { |
625 | reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; |
876 | reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; |
Line 634... | Line 885... | ||
634 | for(i = 0;i < nb_ops; i++) { |
885 | for(i = 0;i < nb_ops; i++) { |
635 | if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) |
886 | if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) |
636 | goto modrm_found; |
887 | goto modrm_found; |
637 | } |
888 | } |
638 | #ifdef ASM_DEBUG |
889 | #ifdef ASM_DEBUG |
639 | error("bad op table"); |
890 | tcc_error("bad op table"); |
640 | #endif |
891 | #endif |
641 | modrm_found: |
892 | modrm_found: |
642 | modrm_index = i; |
893 | modrm_index = i; |
643 | /* if a register is used in another operand then it is |
894 | /* if a register is used in another operand then it is |
644 | used instead of group */ |
895 | used instead of group */ |
Line 653... | Line 904... | ||
653 | 904 | ||
654 | asm_modrm(reg, &ops[modrm_index]); |
905 | asm_modrm(reg, &ops[modrm_index]); |
Line 655... | Line 906... | ||
655 | } |
906 | } |
- | 907 | ||
656 | 908 | /* emit constants */ |
|
657 | /* emit constants */ |
909 | #ifndef TCC_TARGET_X86_64 |
- | 910 | if (pa->opcode == 0x9a || pa->opcode == 0xea) { |
|
- | 911 | /* ljmp or lcall kludge */ |
|
- | 912 | #ifdef I386_ASM_16 |
|
- | 913 | if (s1->seg_size == 16 && o32 == 0) |
|
- | 914 | gen_expr16(&ops[1].e); |
|
658 | if (pa->opcode == 0x9a || pa->opcode == 0xea) { |
915 | else |
659 | /* ljmp or lcall kludge */ |
916 | #endif |
660 | gen_expr32(&ops[1].e); |
917 | gen_expr32(&ops[1].e); |
661 | if (ops[0].e.sym) |
918 | if (ops[0].e.sym) |
662 | error("cannot relocate"); |
919 | tcc_error("cannot relocate"); |
- | 920 | gen_le16(ops[0].e.v); |
|
- | 921 | return; |
|
663 | gen_le16(ops[0].e.v); |
922 | } |
664 | } else { |
923 | #endif |
665 | for(i = 0;i < nb_ops; i++) { |
924 | for(i = 0;i < nb_ops; i++) { |
666 | v = op_type[i]; |
925 | v = op_type[i]; |
667 | if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM8S | OP_ADDR)) { |
926 | if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { |
668 | /* if multiple sizes are given it means we must look |
927 | /* if multiple sizes are given it means we must look |
669 | at the op size */ |
- | |
670 | if (v == (OP_IM8 | OP_IM16 | OP_IM32) || |
928 | at the op size */ |
671 | v == (OP_IM16 | OP_IM32)) { |
929 | if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { |
672 | if (ss == 0) |
930 | if (s == 0) |
673 | v = OP_IM8; |
931 | v = OP_IM8; |
674 | else if (ss == 1) |
932 | else if (s == 1) |
675 | v = OP_IM16; |
933 | v = OP_IM16; |
- | 934 | else if (s == 2 || (v & OP_IM64) == 0) |
|
- | 935 | v = OP_IM32; |
|
676 | else |
936 | else |
677 | v = OP_IM32; |
937 | v = OP_IM64; |
678 | } |
938 | } |
679 | if (v & (OP_IM8 | OP_IM8S)) { |
939 | if (v & (OP_IM8 | OP_IM8S)) { |
680 | if (ops[i].e.sym) |
940 | if (ops[i].e.sym) |
681 | goto error_relocate; |
941 | goto error_relocate; |
- | 942 | g(ops[i].e.v); |
|
- | 943 | } else if (v & OP_IM16) { |
|
- | 944 | #ifdef I386_ASM_16 |
|
- | 945 | if (s1->seg_size == 16) |
|
- | 946 | gen_expr16(&ops[i].e); |
|
682 | g(ops[i].e.v); |
947 | else |
683 | } else if (v & OP_IM16) { |
948 | #endif |
684 | if (ops[i].e.sym) { |
949 | if (ops[i].e.sym) |
685 | error_relocate: |
950 | error_relocate: |
686 | error("cannot relocate"); |
951 | tcc_error("cannot relocate"); |
687 | } |
952 | else |
688 | gen_le16(ops[i].e.v); |
953 | gen_le16(ops[i].e.v); |
689 | } else { |
954 | } else { |
690 | if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
955 | if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
- | 956 | if (is_short_jmp) |
|
- | 957 | g(ops[i].e.v); |
|
- | 958 | #ifdef I386_ASM_16 |
|
- | 959 | else if (s1->seg_size == 16) |
|
691 | if (is_short_jmp) |
960 | gen_disp16(&ops[i].e); |
692 | g(ops[i].e.v); |
961 | #endif |
693 | else |
962 | else |
- | 963 | gen_disp32(&ops[i].e); |
|
- | 964 | } else { |
|
- | 965 | #ifdef I386_ASM_16 |
|
- | 966 | if (s1->seg_size == 16 && !((o32 == 1) && (v & OP_IM32))) |
|
- | 967 | gen_expr16(&ops[i].e); |
|
- | 968 | else |
|
- | 969 | #endif |
|
- | 970 | #ifdef TCC_TARGET_X86_64 |
|
- | 971 | if (v & OP_IM64) |
|
- | 972 | gen_expr64(&ops[i].e); |
|
694 | gen_disp32(&ops[i].e); |
973 | else |
695 | } else { |
974 | #endif |
696 | gen_expr32(&ops[i].e); |
975 | gen_expr32(&ops[i].e); |
- | 976 | } |
|
- | 977 | } |
|
- | 978 | #ifdef I386_ASM_16 |
|
- | 979 | } else if (v & (OP_REG16 | OP_REG32)) { |
|
- | 980 | if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
|
- | 981 | /* jmp $r */ |
|
- | 982 | g(0xE0 + ops[i].reg); |
|
- | 983 | } |
|
- | 984 | #endif |
|
- | 985 | #ifdef TCC_TARGET_X86_64 |
|
- | 986 | } else if (v & (OP_REG32 | OP_REG64)) { |
|
- | 987 | if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) { |
|
697 | } |
988 | /* jmp $r */ |
- | 989 | g(0xE0 + ops[i].reg); |
|
698 | } |
990 | } |
699 | } |
991 | #endif |
- | 992 | } |
|
- | 993 | } |
|
- | 994 | #ifdef I386_ASM_16 |
|
700 | } |
995 | a32 = o32 = 0; |
Line 701... | Line -... | ||
701 | } |
- | |
702 | } |
- | |
703 | - | ||
704 | #define NB_SAVED_REGS 3 |
996 | #endif |
705 | #define NB_ASM_REGS 8 |
997 | } |
706 | 998 | ||
707 | /* return the constraint priority (we allocate first the lowest |
999 | /* return the constraint priority (we allocate first the lowest |
708 | numbered constraints) */ |
1000 | numbered constraints) */ |
Line 742... | Line 1034... | ||
742 | case 'm': |
1034 | case 'm': |
743 | case 'g': |
1035 | case 'g': |
744 | pr = 4; |
1036 | pr = 4; |
745 | break; |
1037 | break; |
746 | default: |
1038 | default: |
747 | error("unknown constraint '%c'", c); |
1039 | tcc_error("unknown constraint '%c'", c); |
748 | pr = 0; |
1040 | pr = 0; |
749 | } |
1041 | } |
750 | if (pr > priority) |
1042 | if (pr > priority) |
751 | priority = pr; |
1043 | priority = pr; |
752 | } |
1044 | } |
Line 763... | Line 1055... | ||
763 | #define REG_OUT_MASK 0x01 |
1055 | #define REG_OUT_MASK 0x01 |
764 | #define REG_IN_MASK 0x02 |
1056 | #define REG_IN_MASK 0x02 |
Line 765... | Line 1057... | ||
765 | 1057 | ||
Line 766... | Line 1058... | ||
766 | #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) |
1058 | #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) |
767 | 1059 | ||
768 | static void asm_compute_constraints(ASMOperand *operands, |
1060 | ST_FUNC void asm_compute_constraints(ASMOperand *operands, |
769 | int nb_operands, int nb_outputs, |
1061 | int nb_operands, int nb_outputs, |
770 | const uint8_t *clobber_regs, |
1062 | const uint8_t *clobber_regs, |
771 | int *pout_reg) |
1063 | int *pout_reg) |
Line 793... | Line 1085... | ||
793 | str = skip_constraint_modifiers(str); |
1085 | str = skip_constraint_modifiers(str); |
794 | if (isnum(*str) || *str == '[') { |
1086 | if (isnum(*str) || *str == '[') { |
795 | /* this is a reference to another constraint */ |
1087 | /* this is a reference to another constraint */ |
796 | k = find_constraint(operands, nb_operands, str, NULL); |
1088 | k = find_constraint(operands, nb_operands, str, NULL); |
797 | if ((unsigned)k >= i || i < nb_outputs) |
1089 | if ((unsigned)k >= i || i < nb_outputs) |
798 | error("invalid reference in constraint %d ('%s')", |
1090 | tcc_error("invalid reference in constraint %d ('%s')", |
799 | i, str); |
1091 | i, str); |
800 | op->ref_index = k; |
1092 | op->ref_index = k; |
801 | if (operands[k].input_index >= 0) |
1093 | if (operands[k].input_index >= 0) |
802 | error("cannot reference twice the same operand"); |
1094 | tcc_error("cannot reference twice the same operand"); |
803 | operands[k].input_index = i; |
1095 | operands[k].input_index = i; |
804 | op->priority = 5; |
1096 | op->priority = 5; |
805 | } else { |
1097 | } else { |
806 | op->priority = constraint_priority(str); |
1098 | op->priority = constraint_priority(str); |
807 | } |
1099 | } |
Line 857... | Line 1149... | ||
857 | case '+': |
1149 | case '+': |
858 | op->is_rw = 1; |
1150 | op->is_rw = 1; |
859 | /* FALL THRU */ |
1151 | /* FALL THRU */ |
860 | case '&': |
1152 | case '&': |
861 | if (j >= nb_outputs) |
1153 | if (j >= nb_outputs) |
862 | error("'%c' modifier can only be applied to outputs", c); |
1154 | tcc_error("'%c' modifier can only be applied to outputs", c); |
863 | reg_mask = REG_IN_MASK | REG_OUT_MASK; |
1155 | reg_mask = REG_IN_MASK | REG_OUT_MASK; |
864 | goto try_next; |
1156 | goto try_next; |
865 | case 'A': |
1157 | case 'A': |
866 | /* allocate both eax and edx */ |
1158 | /* allocate both eax and edx */ |
867 | if (is_reg_allocated(TREG_EAX) || |
1159 | if (is_reg_allocated(TREG_XAX) || |
868 | is_reg_allocated(TREG_EDX)) |
1160 | is_reg_allocated(TREG_XDX)) |
869 | goto try_next; |
1161 | goto try_next; |
870 | op->is_llong = 1; |
1162 | op->is_llong = 1; |
871 | op->reg = TREG_EAX; |
1163 | op->reg = TREG_XAX; |
872 | regs_allocated[TREG_EAX] |= reg_mask; |
1164 | regs_allocated[TREG_XAX] |= reg_mask; |
873 | regs_allocated[TREG_EDX] |= reg_mask; |
1165 | regs_allocated[TREG_XDX] |= reg_mask; |
874 | break; |
1166 | break; |
875 | case 'a': |
1167 | case 'a': |
876 | reg = TREG_EAX; |
1168 | reg = TREG_XAX; |
877 | goto alloc_reg; |
1169 | goto alloc_reg; |
878 | case 'b': |
1170 | case 'b': |
879 | reg = 3; |
1171 | reg = 3; |
880 | goto alloc_reg; |
1172 | goto alloc_reg; |
881 | case 'c': |
1173 | case 'c': |
882 | reg = TREG_ECX; |
1174 | reg = TREG_XCX; |
883 | goto alloc_reg; |
1175 | goto alloc_reg; |
884 | case 'd': |
1176 | case 'd': |
885 | reg = TREG_EDX; |
1177 | reg = TREG_XDX; |
886 | goto alloc_reg; |
1178 | goto alloc_reg; |
887 | case 'S': |
1179 | case 'S': |
888 | reg = 6; |
1180 | reg = 6; |
889 | goto alloc_reg; |
1181 | goto alloc_reg; |
890 | case 'D': |
1182 | case 'D': |
Line 948... | Line 1240... | ||
948 | op->is_memory = 1; |
1240 | op->is_memory = 1; |
949 | } |
1241 | } |
950 | } |
1242 | } |
951 | break; |
1243 | break; |
952 | default: |
1244 | default: |
953 | error("asm constraint %d ('%s') could not be satisfied", |
1245 | tcc_error("asm constraint %d ('%s') could not be satisfied", |
954 | j, op->constraint); |
1246 | j, op->constraint); |
955 | break; |
1247 | break; |
956 | } |
1248 | } |
957 | /* if a reference is present for that operand, we assign it too */ |
1249 | /* if a reference is present for that operand, we assign it too */ |
958 | if (op->input_index >= 0) { |
1250 | if (op->input_index >= 0) { |
Line 971... | Line 1263... | ||
971 | !op->is_memory) { |
1263 | !op->is_memory) { |
972 | for(reg = 0; reg < 8; reg++) { |
1264 | for(reg = 0; reg < 8; reg++) { |
973 | if (!(regs_allocated[reg] & REG_OUT_MASK)) |
1265 | if (!(regs_allocated[reg] & REG_OUT_MASK)) |
974 | goto reg_found2; |
1266 | goto reg_found2; |
975 | } |
1267 | } |
976 | error("could not find free output register for reloading"); |
1268 | tcc_error("could not find free output register for reloading"); |
977 | reg_found2: |
1269 | reg_found2: |
978 | *pout_reg = reg; |
1270 | *pout_reg = reg; |
979 | break; |
1271 | break; |
980 | } |
1272 | } |
981 | } |
1273 | } |
Line 995... | Line 1287... | ||
995 | if (*pout_reg >= 0) |
1287 | if (*pout_reg >= 0) |
996 | printf("out_reg=%d\n", *pout_reg); |
1288 | printf("out_reg=%d\n", *pout_reg); |
997 | #endif |
1289 | #endif |
998 | } |
1290 | } |
Line 999... | Line 1291... | ||
999 | 1291 | ||
1000 | static void subst_asm_operand(CString *add_str, |
1292 | ST_FUNC void subst_asm_operand(CString *add_str, |
1001 | SValue *sv, int modifier) |
1293 | SValue *sv, int modifier) |
1002 | { |
1294 | { |
1003 | int r, reg, size, val; |
1295 | int r, reg, size, val; |
Line 1004... | Line 1296... | ||
1004 | char buf[64]; |
1296 | char buf[64]; |
1005 | 1297 | ||
1006 | r = sv->r; |
1298 | r = sv->r; |
1007 | if ((r & VT_VALMASK) == VT_CONST) { |
1299 | if ((r & VT_VALMASK) == VT_CONST) { |
1008 | if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n') |
1300 | if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n') |
1009 | cstr_ccat(add_str, '$'); |
1301 | cstr_ccat(add_str, '$'); |
1010 | if (r & VT_SYM) { |
1302 | if (r & VT_SYM) { |
1011 | cstr_cat(add_str, get_tok_str(sv->sym->v, NULL)); |
1303 | cstr_cat(add_str, get_tok_str(sv->sym->v, NULL), -1); |
1012 | if (sv->c.i != 0) { |
1304 | if ((uint32_t)sv->c.i != 0) { |
1013 | cstr_ccat(add_str, '+'); |
1305 | cstr_ccat(add_str, '+'); |
1014 | } else { |
1306 | } else { |
1015 | return; |
1307 | return; |
1016 | } |
1308 | } |
1017 | } |
1309 | } |
1018 | val = sv->c.i; |
1310 | val = sv->c.i; |
1019 | if (modifier == 'n') |
1311 | if (modifier == 'n') |
1020 | val = -val; |
1312 | val = -val; |
1021 | snprintf(buf, sizeof(buf), "%d", sv->c.i); |
1313 | snprintf(buf, sizeof(buf), "%d", (int)sv->c.i); |
1022 | cstr_cat(add_str, buf); |
1314 | cstr_cat(add_str, buf, -1); |
1023 | } else if ((r & VT_VALMASK) == VT_LOCAL) { |
1315 | } else if ((r & VT_VALMASK) == VT_LOCAL) { |
1024 | snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i); |
1316 | snprintf(buf, sizeof(buf), "%d(%%ebp)", (int)sv->c.i); |
1025 | cstr_cat(add_str, buf); |
1317 | cstr_cat(add_str, buf, -1); |
1026 | } else if (r & VT_LVAL) { |
1318 | } else if (r & VT_LVAL) { |
1027 | reg = r & VT_VALMASK; |
1319 | reg = r & VT_VALMASK; |
1028 | if (reg >= VT_CONST) |
1320 | if (reg >= VT_CONST) |
1029 | error("internal compiler error"); |
1321 | tcc_error("internal compiler error"); |
1030 | snprintf(buf, sizeof(buf), "(%%%s)", |
1322 | snprintf(buf, sizeof(buf), "(%%%s)", |
1031 | get_tok_str(TOK_ASM_eax + reg, NULL)); |
1323 | get_tok_str(TOK_ASM_eax + reg, NULL)); |
1032 | cstr_cat(add_str, buf); |
1324 | cstr_cat(add_str, buf, -1); |
1033 | } else { |
1325 | } else { |
1034 | /* register case */ |
1326 | /* register case */ |
1035 | reg = r & VT_VALMASK; |
1327 | reg = r & VT_VALMASK; |
Line 1036... | Line 1328... | ||
1036 | if (reg >= VT_CONST) |
1328 | if (reg >= VT_CONST) |
1037 | error("internal compiler error"); |
1329 | tcc_error("internal compiler error"); |
1038 | 1330 | ||
1039 | /* choose register operand size */ |
1331 | /* choose register operand size */ |
1040 | if ((sv->type.t & VT_BTYPE) == VT_BYTE) |
1332 | if ((sv->type.t & VT_BTYPE) == VT_BYTE) |
- | 1333 | size = 1; |
|
- | 1334 | else if ((sv->type.t & VT_BTYPE) == VT_SHORT) |
|
- | 1335 | size = 2; |
|
- | 1336 | #ifdef TCC_TARGET_X86_64 |
|
1041 | size = 1; |
1337 | else if ((sv->type.t & VT_BTYPE) == VT_LLONG) |
1042 | else if ((sv->type.t & VT_BTYPE) == VT_SHORT) |
1338 | size = 8; |
1043 | size = 2; |
1339 | #endif |
1044 | else |
1340 | else |
Line 1045... | Line 1341... | ||
1045 | size = 4; |
1341 | size = 4; |
1046 | if (size == 1 && reg >= 4) |
1342 | if (size == 1 && reg >= 4) |
1047 | size = 4; |
1343 | size = 4; |
1048 | 1344 | ||
1049 | if (modifier == 'b') { |
1345 | if (modifier == 'b') { |
1050 | if (reg >= 4) |
1346 | if (reg >= 4) |
1051 | error("cannot use byte register"); |
1347 | tcc_error("cannot use byte register"); |
1052 | size = 1; |
1348 | size = 1; |
1053 | } else if (modifier == 'h') { |
1349 | } else if (modifier == 'h') { |
1054 | if (reg >= 4) |
1350 | if (reg >= 4) |
- | 1351 | tcc_error("cannot use byte register"); |
|
- | 1352 | size = -1; |
|
- | 1353 | } else if (modifier == 'w') { |
|
- | 1354 | size = 2; |
|
1055 | error("cannot use byte register"); |
1355 | #ifdef TCC_TARGET_X86_64 |
Line 1056... | Line 1356... | ||
1056 | size = -1; |
1356 | } else if (modifier == 'q') { |
1057 | } else if (modifier == 'w') { |
1357 | size = 8; |
1058 | size = 2; |
1358 | #endif |
Line 1069... | Line 1369... | ||
1069 | reg = TOK_ASM_ax + reg; |
1369 | reg = TOK_ASM_ax + reg; |
1070 | break; |
1370 | break; |
1071 | default: |
1371 | default: |
1072 | reg = TOK_ASM_eax + reg; |
1372 | reg = TOK_ASM_eax + reg; |
1073 | break; |
1373 | break; |
- | 1374 | #ifdef TCC_TARGET_X86_64 |
|
- | 1375 | case 8: |
|
- | 1376 | reg = TOK_ASM_rax + reg; |
|
- | 1377 | break; |
|
- | 1378 | #endif |
|
1074 | } |
1379 | } |
1075 | snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); |
1380 | snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL)); |
1076 | cstr_cat(add_str, buf); |
1381 | cstr_cat(add_str, buf, -1); |
1077 | } |
1382 | } |
1078 | } |
1383 | } |
Line 1079... | Line 1384... | ||
1079 | 1384 | ||
1080 | /* generate prolog and epilog code for asm statment */ |
1385 | /* generate prolog and epilog code for asm statement */ |
1081 | static void asm_gen_code(ASMOperand *operands, int nb_operands, |
1386 | ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, |
1082 | int nb_outputs, int is_output, |
1387 | int nb_outputs, int is_output, |
1083 | uint8_t *clobber_regs, |
1388 | uint8_t *clobber_regs, |
1084 | int out_reg) |
1389 | int out_reg) |
1085 | { |
1390 | { |
Line 1097... | Line 1402... | ||
1097 | } |
1402 | } |
1098 | if (!is_output) { |
1403 | if (!is_output) { |
1099 | /* generate reg save code */ |
1404 | /* generate reg save code */ |
1100 | for(i = 0; i < NB_SAVED_REGS; i++) { |
1405 | for(i = 0; i < NB_SAVED_REGS; i++) { |
1101 | reg = reg_saved[i]; |
1406 | reg = reg_saved[i]; |
1102 | if (regs_allocated[reg]) |
1407 | if (regs_allocated[reg]) { |
- | 1408 | #ifdef I386_ASM_16 |
|
- | 1409 | if (tcc_state->seg_size == 16) |
|
- | 1410 | g(0x66); |
|
- | 1411 | #endif |
|
1103 | g(0x50 + reg); |
1412 | g(0x50 + reg); |
1104 | } |
1413 | } |
- | 1414 | } |
|
Line 1105... | Line 1415... | ||
1105 | 1415 | ||
1106 | /* generate load code */ |
1416 | /* generate load code */ |
1107 | for(i = 0; i < nb_operands; i++) { |
1417 | for(i = 0; i < nb_operands; i++) { |
1108 | op = &operands[i]; |
1418 | op = &operands[i]; |
Line 1119... | Line 1429... | ||
1119 | /* load value in register */ |
1429 | /* load value in register */ |
1120 | load(op->reg, op->vt); |
1430 | load(op->reg, op->vt); |
1121 | if (op->is_llong) { |
1431 | if (op->is_llong) { |
1122 | SValue sv; |
1432 | SValue sv; |
1123 | sv = *op->vt; |
1433 | sv = *op->vt; |
1124 | sv.c.ul += 4; |
1434 | sv.c.i += 4; |
1125 | load(TREG_EDX, &sv); |
1435 | load(TREG_XDX, &sv); |
1126 | } |
1436 | } |
1127 | } |
1437 | } |
1128 | } |
1438 | } |
1129 | } |
1439 | } |
1130 | } else { |
1440 | } else { |
Line 1145... | Line 1455... | ||
1145 | } else { |
1455 | } else { |
1146 | store(op->reg, op->vt); |
1456 | store(op->reg, op->vt); |
1147 | if (op->is_llong) { |
1457 | if (op->is_llong) { |
1148 | SValue sv; |
1458 | SValue sv; |
1149 | sv = *op->vt; |
1459 | sv = *op->vt; |
1150 | sv.c.ul += 4; |
1460 | sv.c.i += 4; |
1151 | store(TREG_EDX, &sv); |
1461 | store(TREG_XDX, &sv); |
1152 | } |
1462 | } |
1153 | } |
1463 | } |
1154 | } |
1464 | } |
1155 | } |
1465 | } |
1156 | /* generate reg restore code */ |
1466 | /* generate reg restore code */ |
1157 | for(i = NB_SAVED_REGS - 1; i >= 0; i--) { |
1467 | for(i = NB_SAVED_REGS - 1; i >= 0; i--) { |
1158 | reg = reg_saved[i]; |
1468 | reg = reg_saved[i]; |
1159 | if (regs_allocated[reg]) |
1469 | if (regs_allocated[reg]) { |
- | 1470 | #ifdef I386_ASM_16 |
|
- | 1471 | if (tcc_state->seg_size == 16) |
|
- | 1472 | g(0x66); |
|
- | 1473 | #endif |
|
1160 | g(0x58 + reg); |
1474 | g(0x58 + reg); |
1161 | } |
1475 | } |
1162 | } |
1476 | } |
1163 | } |
1477 | } |
- | 1478 | } |
|
Line 1164... | Line 1479... | ||
1164 | 1479 | ||
1165 | static void asm_clobber(uint8_t *clobber_regs, const char *str) |
1480 | ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) |
1166 | { |
1481 | { |
1167 | int reg; |
1482 | int reg; |
Line 1168... | Line 1483... | ||
1168 | TokenSym *ts; |
1483 | TokenSym *ts; |
Line 1174... | Line 1489... | ||
1174 | reg = ts->tok; |
1489 | reg = ts->tok; |
1175 | if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { |
1490 | if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { |
1176 | reg -= TOK_ASM_eax; |
1491 | reg -= TOK_ASM_eax; |
1177 | } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { |
1492 | } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { |
1178 | reg -= TOK_ASM_ax; |
1493 | reg -= TOK_ASM_ax; |
- | 1494 | #ifdef TCC_TARGET_X86_64 |
|
- | 1495 | } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { |
|
- | 1496 | reg -= TOK_ASM_rax; |
|
- | 1497 | #endif |
|
1179 | } else { |
1498 | } else { |
1180 | error("invalid clobber register '%s'", str); |
1499 | tcc_error("invalid clobber register '%s'", str); |
1181 | } |
1500 | } |
1182 | clobber_regs[reg] = 1; |
1501 | clobber_regs[reg] = 1; |
1183 | }=>=>>>>>>>>>>>>> |
1502 | }=>=>=>>>>>>>>>>>>> |