Rev 647 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 647 | Rev 6429 | ||
---|---|---|---|
Line 16... | Line 16... | ||
16 | * You should have received a copy of the GNU Lesser General Public |
16 | * 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 |
17 | * 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 |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
19 | */ |
Line -... | Line 20... | ||
- | 20 | ||
- | 21 | #ifdef TARGET_DEFS_ONLY |
|
20 | 22 | ||
21 | /* number of available registers */ |
23 | /* number of available registers */ |
- | 24 | #define NB_REGS 4 |
|
Line 22... | Line 25... | ||
22 | #define NB_REGS 4 |
25 | #define NB_ASM_REGS 8 |
23 | 26 | ||
24 | /* a register can belong to several classes. The classes must be |
27 | /* a register can belong to several classes. The classes must be |
25 | sorted from more general to more precise (see gv2() code which does |
28 | sorted from more general to more precise (see gv2() code which does |
Line 38... | Line 41... | ||
38 | enum { |
41 | enum { |
39 | TREG_EAX = 0, |
42 | TREG_EAX = 0, |
40 | TREG_ECX, |
43 | TREG_ECX, |
41 | TREG_EDX, |
44 | TREG_EDX, |
42 | TREG_ST0, |
45 | TREG_ST0, |
43 | }; |
- | |
44 | - | ||
45 | int reg_classes[NB_REGS] = { |
46 | TREG_ESP = 4 |
46 | /* eax */ RC_INT | RC_EAX, |
- | |
47 | /* ecx */ RC_INT | RC_ECX, |
- | |
48 | /* edx */ RC_INT | RC_EDX, |
- | |
49 | /* st0 */ RC_FLOAT | RC_ST0, |
- | |
50 | }; |
47 | }; |
Line 51... | Line 48... | ||
51 | 48 | ||
52 | /* return registers for function */ |
49 | /* return registers for function */ |
53 | #define REG_IRET TREG_EAX /* single word int return register */ |
50 | #define REG_IRET TREG_EAX /* single word int return register */ |
Line 57... | Line 54... | ||
57 | /* defined if function parameters must be evaluated in reverse order */ |
54 | /* defined if function parameters must be evaluated in reverse order */ |
58 | #define INVERT_FUNC_PARAMS |
55 | #define INVERT_FUNC_PARAMS |
Line 59... | Line 56... | ||
59 | 56 | ||
60 | /* defined if structures are passed as pointers. Otherwise structures |
57 | /* defined if structures are passed as pointers. Otherwise structures |
61 | are directly pushed on stack. */ |
58 | are directly pushed on stack. */ |
Line 62... | Line 59... | ||
62 | //#define FUNC_STRUCT_PARAM_AS_PTR |
59 | /* #define FUNC_STRUCT_PARAM_AS_PTR */ |
63 | 60 | ||
Line 64... | Line 61... | ||
64 | /* pointer size, in bytes */ |
61 | /* pointer size, in bytes */ |
65 | #define PTR_SIZE 4 |
62 | #define PTR_SIZE 4 |
66 | 63 | ||
67 | /* long double size and alignment, in bytes */ |
64 | /* long double size and alignment, in bytes */ |
68 | #define LDOUBLE_SIZE 12 |
65 | #define LDOUBLE_SIZE 12 |
Line -... | Line 66... | ||
- | 66 | #define LDOUBLE_ALIGN 4 |
|
- | 67 | /* maximum alignment (for aligned attribute support) */ |
|
- | 68 | #define MAX_ALIGN 8 |
|
69 | #define LDOUBLE_ALIGN 4 |
69 | |
70 | /* maximum alignment (for aligned attribute support) */ |
70 | |
Line 71... | Line 71... | ||
71 | #define MAX_ALIGN 8 |
71 | #define psym oad |
Line 72... | Line 72... | ||
72 | 72 | ||
73 | /******************************************************/ |
73 | /******************************************************/ |
- | 74 | /* ELF defines */ |
|
74 | /* ELF defines */ |
75 | |
75 | 76 | #define EM_TCC_TARGET EM_386 |
|
Line 76... | Line 77... | ||
76 | #define EM_TCC_TARGET EM_386 |
77 | |
77 | 78 | /* relocation type for 32 bit data relocation */ |
|
Line 78... | Line 79... | ||
78 | /* relocation type for 32 bit data relocation */ |
79 | #define R_DATA_32 R_386_32 |
- | 80 | #define R_DATA_PTR R_386_32 |
|
- | 81 | #define R_JMP_SLOT R_386_JMP_SLOT |
|
- | 82 | #define R_COPY R_386_COPY |
|
- | 83 | ||
- | 84 | #define ELF_START_ADDR 0x08048000 |
|
- | 85 | #define ELF_PAGE_SIZE 0x1000 |
|
- | 86 | ||
- | 87 | /******************************************************/ |
|
- | 88 | #else /* ! TARGET_DEFS_ONLY */ |
|
- | 89 | /******************************************************/ |
|
Line 79... | Line 90... | ||
79 | #define R_DATA_32 R_386_32 |
90 | #include "tcc.h" |
80 | #define R_JMP_SLOT R_386_JMP_SLOT |
- | |
81 | #define R_COPY R_386_COPY |
91 | |
- | 92 | ST_DATA const int reg_classes[NB_REGS] = { |
|
- | 93 | /* eax */ RC_INT | RC_EAX, |
|
- | 94 | /* ecx */ RC_INT | RC_ECX, |
|
Line 82... | Line 95... | ||
82 | 95 | /* edx */ RC_INT | RC_EDX, |
|
83 | #define ELF_START_ADDR 0x08048000 |
96 | /* st0 */ RC_FLOAT | RC_ST0, |
84 | #define ELF_PAGE_SIZE 0x1000 |
97 | }; |
85 | 98 | ||
86 | /******************************************************/ |
99 | static unsigned long func_sub_sp_offset; |
87 | 100 | static int func_ret_sub; |
|
88 | static unsigned long func_sub_sp_offset; |
101 | #ifdef CONFIG_TCC_BCHECK |
89 | static unsigned long func_bound_offset; |
102 | static addr_t func_bound_offset; |
90 | static int func_ret_sub; |
103 | #endif |
91 | 104 | ||
Line 92... | Line 105... | ||
92 | /* XXX: make it faster ? */ |
105 | /* XXX: make it faster ? */ |
93 | void g(int c) |
106 | ST_FUNC void g(int c) |
94 | { |
107 | { |
95 | int ind1; |
108 | int ind1; |
96 | ind1 = ind + 1; |
109 | ind1 = ind + 1; |
97 | if (ind1 > cur_text_section->data_allocated) |
110 | if (ind1 > cur_text_section->data_allocated) |
98 | section_realloc(cur_text_section, ind1); |
111 | section_realloc(cur_text_section, ind1); |
Line -... | Line 112... | ||
- | 112 | cur_text_section->data[ind] = c; |
|
- | 113 | ind = ind1; |
|
- | 114 | } |
|
- | 115 | ||
- | 116 | ST_FUNC void o(unsigned int c) |
|
- | 117 | { |
|
99 | cur_text_section->data[ind] = c; |
118 | while (c) { |
100 | ind = ind1; |
119 | g(c); |
101 | } |
120 | c = c >> 8; |
102 | 121 | } |
|
103 | void o(unsigned int c) |
122 | } |
104 | { |
123 | |
105 | while (c) { |
124 | ST_FUNC void gen_le16(int v) |
Line 106... | Line 125... | ||
106 | g(c); |
125 | { |
107 | c = c >> 8; |
126 | g(v); |
108 | } |
127 | g(v >> 8); |
109 | } |
- | |
110 | 128 | } |
|
111 | void gen_le32(int c) |
129 | |
112 | { |
130 | ST_FUNC void gen_le32(int c) |
113 | g(c); |
131 | { |
114 | g(c >> 8); |
132 | g(c); |
115 | g(c >> 16); |
133 | g(c >> 8); |
116 | g(c >> 24); |
134 | g(c >> 16); |
Line 117... | Line 135... | ||
117 | } |
135 | g(c >> 24); |
118 | 136 | } |
|
119 | /* output a symbol and patch all calls to it */ |
137 | |
120 | void gsym_addr(int t, int a) |
138 | /* output a symbol and patch all calls to it */ |
Line 121... | Line 139... | ||
121 | { |
139 | ST_FUNC void gsym_addr(int t, int a) |
122 | int n, *ptr; |
140 | { |
123 | while (t) { |
141 | while (t) { |
Line 124... | Line 142... | ||
124 | ptr = (int *)(cur_text_section->data + t); |
142 | unsigned char *ptr = cur_text_section->data + t; |
125 | n = *ptr; /* next value */ |
143 | uint32_t n = read32le(ptr); /* next value */ |
126 | *ptr = a - t - 4; |
144 | write32le(ptr, a - t - 4); |
127 | t = n; |
145 | t = n; |
Line 128... | Line 146... | ||
128 | } |
146 | } |
129 | } |
147 | } |
130 | 148 | ||
131 | void gsym(int t) |
149 | ST_FUNC void gsym(int t) |
132 | { |
150 | { |
133 | gsym_addr(t, ind); |
151 | gsym_addr(t, ind); |
134 | } |
152 | } |
135 | 153 | ||
136 | /* psym is used to put an instruction with a data field which is a |
154 | /* psym is used to put an instruction with a data field which is a |
Line 137... | Line 155... | ||
137 | reference to a symbol. It is in fact the same as oad ! */ |
155 | reference to a symbol. It is in fact the same as oad ! */ |
138 | #define psym oad |
156 | #define psym oad |
139 | 157 | ||
140 | /* instruction + 4 bytes data. Return the address of the data */ |
158 | /* instruction + 4 bytes data. Return the address of the data */ |
141 | static int oad(int c, int s) |
159 | ST_FUNC int oad(int c, int s) |
142 | { |
160 | { |
143 | int ind1; |
161 | int ind1; |
Line -... | Line 162... | ||
- | 162 | ||
- | 163 | o(c); |
|
- | 164 | ind1 = ind + 4; |
|
- | 165 | if (ind1 > cur_text_section->data_allocated) |
|
- | 166 | section_realloc(cur_text_section, ind1); |
|
- | 167 | write32le(cur_text_section->data + ind, s); |
|
- | 168 | s = ind; |
|
144 | 169 | ind = ind1; |
|
145 | o(c); |
170 | return s; |
146 | ind1 = ind + 4; |
171 | } |
147 | if (ind1 > cur_text_section->data_allocated) |
172 | |
148 | section_realloc(cur_text_section, ind1); |
173 | /* output constant with relocation if 'r & VT_SYM' is true */ |
Line 181... | Line 206... | ||
181 | } else { |
206 | } else { |
182 | g(0x00 | op_reg | (r & VT_VALMASK)); |
207 | g(0x00 | op_reg | (r & VT_VALMASK)); |
183 | } |
208 | } |
184 | } |
209 | } |
Line 185... | Line -... | ||
185 | - | ||
186 | 210 | ||
187 | /* load 'r' from value 'sv' */ |
211 | /* load 'r' from value 'sv' */ |
188 | void load(int r, SValue *sv) |
212 | ST_FUNC void load(int r, SValue *sv) |
189 | { |
213 | { |
190 | int v, t, ft, fc, fr; |
214 | int v, t, ft, fc, fr; |
Line -... | Line 215... | ||
- | 215 | SValue v1; |
|
- | 216 | ||
- | 217 | #ifdef TCC_TARGET_PE |
|
- | 218 | SValue v2; |
|
- | 219 | sv = pe_getimport(sv, &v2); |
|
191 | SValue v1; |
220 | #endif |
192 | 221 | ||
193 | fr = sv->r; |
222 | fr = sv->r; |
- | 223 | ft = sv->type.t; |
|
- | 224 | fc = sv->c.i; |
|
Line 194... | Line 225... | ||
194 | ft = sv->type.t; |
225 | |
195 | fc = sv->c.ul; |
226 | ft &= ~(VT_VOLATILE | VT_CONSTANT); |
196 | 227 | ||
197 | v = fr & VT_VALMASK; |
228 | v = fr & VT_VALMASK; |
198 | if (fr & VT_LVAL) { |
229 | if (fr & VT_LVAL) { |
199 | if (v == VT_LLOCAL) { |
230 | if (v == VT_LLOCAL) { |
200 | v1.type.t = VT_INT; |
- | |
201 | v1.r = VT_LOCAL | VT_LVAL; |
231 | v1.type.t = VT_INT; |
- | 232 | v1.r = VT_LOCAL | VT_LVAL; |
|
- | 233 | v1.c.i = fc; |
|
- | 234 | fr = r; |
|
202 | v1.c.ul = fc; |
235 | if (!(reg_classes[fr] & RC_INT)) |
203 | load(r, &v1); |
236 | fr = get_reg(RC_INT); |
204 | fr = r; |
237 | load(fr, &v1); |
205 | } |
238 | } |
206 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
239 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
207 | o(0xd9); /* flds */ |
240 | o(0xd9); /* flds */ |
208 | r = 0; |
241 | r = 0; |
209 | } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
242 | } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
210 | o(0xdd); /* fldl */ |
243 | o(0xdd); /* fldl */ |
211 | r = 0; |
244 | r = 0; |
212 | } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
245 | } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
213 | o(0xdb); /* fldt */ |
246 | o(0xdb); /* fldt */ |
214 | r = 5; |
247 | r = 5; |
215 | } else if ((ft & VT_TYPE) == VT_BYTE) { |
248 | } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { |
216 | o(0xbe0f); /* movsbl */ |
249 | o(0xbe0f); /* movsbl */ |
217 | } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { |
250 | } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { |
Line 227... | Line 260... | ||
227 | } else { |
260 | } else { |
228 | if (v == VT_CONST) { |
261 | if (v == VT_CONST) { |
229 | o(0xb8 + r); /* mov $xx, r */ |
262 | o(0xb8 + r); /* mov $xx, r */ |
230 | gen_addr32(fr, sv->sym, fc); |
263 | gen_addr32(fr, sv->sym, fc); |
231 | } else if (v == VT_LOCAL) { |
264 | } else if (v == VT_LOCAL) { |
- | 265 | if (fc) { |
|
232 | o(0x8d); /* lea xxx(%ebp), r */ |
266 | o(0x8d); /* lea xxx(%ebp), r */ |
233 | gen_modrm(r, VT_LOCAL, sv->sym, fc); |
267 | gen_modrm(r, VT_LOCAL, sv->sym, fc); |
- | 268 | } else { |
|
- | 269 | o(0x89); |
|
- | 270 | o(0xe8 + r); /* mov %ebp, r */ |
|
- | 271 | } |
|
234 | } else if (v == VT_CMP) { |
272 | } else if (v == VT_CMP) { |
235 | oad(0xb8 + r, 0); /* mov $0, r */ |
273 | oad(0xb8 + r, 0); /* mov $0, r */ |
236 | o(0x0f); /* setxx %br */ |
274 | o(0x0f); /* setxx %br */ |
237 | o(fc); |
275 | o(fc); |
238 | o(0xc0 + r); |
276 | o(0xc0 + r); |
Line 248... | Line 286... | ||
248 | } |
286 | } |
249 | } |
287 | } |
250 | } |
288 | } |
Line 251... | Line 289... | ||
251 | 289 | ||
252 | /* store register 'r' in lvalue 'v' */ |
290 | /* store register 'r' in lvalue 'v' */ |
253 | void store(int r, SValue *v) |
291 | ST_FUNC void store(int r, SValue *v) |
254 | { |
292 | { |
Line -... | Line 293... | ||
- | 293 | int fr, bt, ft, fc; |
|
- | 294 | ||
- | 295 | #ifdef TCC_TARGET_PE |
|
- | 296 | SValue v2; |
|
- | 297 | v = pe_getimport(v, &v2); |
|
255 | int fr, bt, ft, fc; |
298 | #endif |
256 | 299 | ||
257 | ft = v->type.t; |
300 | ft = v->type.t; |
- | 301 | fc = v->c.i; |
|
258 | fc = v->c.ul; |
302 | fr = v->r & VT_VALMASK; |
259 | fr = v->r & VT_VALMASK; |
303 | ft &= ~(VT_VOLATILE | VT_CONSTANT); |
260 | bt = ft & VT_BTYPE; |
304 | bt = ft & VT_BTYPE; |
261 | /* XXX: incorrect if float reg to reg */ |
305 | /* XXX: incorrect if float reg to reg */ |
262 | if (bt == VT_FLOAT) { |
306 | if (bt == VT_FLOAT) { |
Line 294... | Line 338... | ||
294 | } else { |
338 | } else { |
295 | oad(0xc481, val); /* add $xxx, %esp */ |
339 | oad(0xc481, val); /* add $xxx, %esp */ |
296 | } |
340 | } |
297 | } |
341 | } |
Line -... | Line 342... | ||
- | 342 | ||
- | 343 | static void gen_static_call(int v) |
|
- | 344 | { |
|
- | 345 | Sym *sym; |
|
- | 346 | ||
- | 347 | sym = external_global_sym(v, &func_old_type, 0); |
|
- | 348 | oad(0xe8, -4); |
|
- | 349 | greloc(cur_text_section, sym, ind-4, R_386_PC32); |
|
- | 350 | } |
|
298 | 351 | ||
299 | /* 'is_jmp' is '1' if it is a jump */ |
352 | /* 'is_jmp' is '1' if it is a jump */ |
300 | static void gcall_or_jmp(int is_jmp) |
353 | static void gcall_or_jmp(int is_jmp) |
301 | { |
354 | { |
302 | int r; |
355 | int r; |
Line 309... | Line 362... | ||
309 | } else { |
362 | } else { |
310 | /* put an empty PC32 relocation */ |
363 | /* put an empty PC32 relocation */ |
311 | put_elf_reloc(symtab_section, cur_text_section, |
364 | put_elf_reloc(symtab_section, cur_text_section, |
312 | ind + 1, R_386_PC32, 0); |
365 | ind + 1, R_386_PC32, 0); |
313 | } |
366 | } |
314 | oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */ |
367 | oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ |
315 | } else { |
368 | } else { |
316 | /* otherwise, indirect call */ |
369 | /* otherwise, indirect call */ |
317 | r = gv(RC_INT); |
370 | r = gv(RC_INT); |
318 | o(0xff); /* call/jmp *r */ |
371 | o(0xff); /* call/jmp *r */ |
319 | o(0xd0 + r + (is_jmp << 4)); |
372 | o(0xd0 + r + (is_jmp << 4)); |
320 | } |
373 | } |
321 | } |
374 | } |
Line 322... | Line 375... | ||
322 | 375 | ||
- | 376 | static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; |
|
- | 377 | static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; |
|
- | 378 | ||
- | 379 | /* Return the number of registers needed to return the struct, or 0 if |
|
- | 380 | returning via struct pointer. */ |
|
- | 381 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) |
|
- | 382 | { |
|
- | 383 | #ifdef TCC_TARGET_PE |
|
- | 384 | int size, align; |
|
- | 385 | ||
- | 386 | *ret_align = 1; // Never have to re-align return values for x86 |
|
- | 387 | *regsize = 4; |
|
- | 388 | size = type_size(vt, &align); |
|
- | 389 | if (size > 8) { |
|
- | 390 | return 0; |
|
- | 391 | } else if (size > 4) { |
|
- | 392 | ret->ref = NULL; |
|
- | 393 | ret->t = VT_LLONG; |
|
- | 394 | return 1; |
|
- | 395 | } else { |
|
- | 396 | ret->ref = NULL; |
|
- | 397 | ret->t = VT_INT; |
|
- | 398 | return 1; |
|
- | 399 | } |
|
- | 400 | #else |
|
- | 401 | *ret_align = 1; // Never have to re-align return values for x86 |
|
- | 402 | return 0; |
|
- | 403 | #endif |
|
Line 323... | Line 404... | ||
323 | static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX }; |
404 | } |
324 | 405 | ||
325 | /* Generate function call. The function address is pushed first, then |
406 | /* Generate function call. The function address is pushed first, then |
326 | all the parameters in call order. This functions pops all the |
407 | all the parameters in call order. This functions pops all the |
327 | parameters and the function address. */ |
408 | parameters and the function address. */ |
328 | void gfunc_call(int nb_args) |
409 | ST_FUNC void gfunc_call(int nb_args) |
329 | { |
410 | { |
Line 330... | Line 411... | ||
330 | int size, align, r, args_size, i, func_call; |
411 | int size, align, r, args_size, i, func_call; |
Line 377... | Line 458... | ||
377 | } |
458 | } |
378 | vtop--; |
459 | vtop--; |
379 | } |
460 | } |
380 | save_regs(0); /* save used temporary registers */ |
461 | save_regs(0); /* save used temporary registers */ |
381 | func_sym = vtop->type.ref; |
462 | func_sym = vtop->type.ref; |
382 | func_call = func_sym->r; |
463 | func_call = func_sym->a.func_call; |
383 | /* fast call case */ |
464 | /* fast call case */ |
384 | if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { |
465 | if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || |
- | 466 | func_call == FUNC_FASTCALLW) { |
|
385 | int fastcall_nb_regs; |
467 | int fastcall_nb_regs; |
- | 468 | uint8_t *fastcall_regs_ptr; |
|
- | 469 | if (func_call == FUNC_FASTCALLW) { |
|
- | 470 | fastcall_regs_ptr = fastcallw_regs; |
|
- | 471 | fastcall_nb_regs = 2; |
|
- | 472 | } else { |
|
- | 473 | fastcall_regs_ptr = fastcall_regs; |
|
386 | fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
474 | fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
- | 475 | } |
|
387 | for(i = 0;i < fastcall_nb_regs; i++) { |
476 | for(i = 0;i < fastcall_nb_regs; i++) { |
388 | if (args_size <= 0) |
477 | if (args_size <= 0) |
389 | break; |
478 | break; |
390 | o(0x58 + fastcall_regs[i]); /* pop r */ |
479 | o(0x58 + fastcall_regs_ptr[i]); /* pop r */ |
391 | /* XXX: incorrect for struct/floats */ |
480 | /* XXX: incorrect for struct/floats */ |
392 | args_size -= 4; |
481 | args_size -= 4; |
393 | } |
482 | } |
394 | } |
483 | } |
- | 484 | #ifndef TCC_TARGET_PE |
|
- | 485 | else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT) |
|
- | 486 | args_size -= 4; |
|
- | 487 | #endif |
|
395 | gcall_or_jmp(0); |
488 | gcall_or_jmp(0); |
- | 489 | ||
396 | if (args_size && func_sym->r != FUNC_STDCALL) |
490 | if (args_size && func_call != FUNC_STDCALL) |
397 | gadd_sp(args_size); |
491 | gadd_sp(args_size); |
398 | vtop--; |
492 | vtop--; |
399 | } |
493 | } |
Line 400... | Line 494... | ||
400 | 494 | ||
Line 403... | Line 497... | ||
403 | #else |
497 | #else |
404 | #define FUNC_PROLOG_SIZE 9 |
498 | #define FUNC_PROLOG_SIZE 9 |
405 | #endif |
499 | #endif |
Line 406... | Line 500... | ||
406 | 500 | ||
407 | /* generate function prolog of type 't' */ |
501 | /* generate function prolog of type 't' */ |
408 | void gfunc_prolog(CType *func_type) |
502 | ST_FUNC void gfunc_prolog(CType *func_type) |
409 | { |
503 | { |
410 | int addr, align, size, func_call, fastcall_nb_regs; |
504 | int addr, align, size, func_call, fastcall_nb_regs; |
- | 505 | int param_index, param_addr; |
|
411 | int param_index, param_addr; |
506 | uint8_t *fastcall_regs_ptr; |
412 | Sym *sym; |
507 | Sym *sym; |
Line 413... | Line 508... | ||
413 | CType *type; |
508 | CType *type; |
414 | 509 | ||
415 | sym = func_type->ref; |
510 | sym = func_type->ref; |
416 | func_call = sym->r; |
511 | func_call = sym->a.func_call; |
- | 512 | addr = 8; |
|
- | 513 | loc = 0; |
|
417 | addr = 8; |
514 | func_vc = 0; |
418 | loc = 0; |
515 | |
- | 516 | if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { |
|
- | 517 | fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
|
- | 518 | fastcall_regs_ptr = fastcall_regs; |
|
- | 519 | } else if (func_call == FUNC_FASTCALLW) { |
|
419 | if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) { |
520 | fastcall_nb_regs = 2; |
420 | fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; |
521 | fastcall_regs_ptr = fastcallw_regs; |
- | 522 | } else { |
|
421 | } else { |
523 | fastcall_nb_regs = 0; |
422 | fastcall_nb_regs = 0; |
524 | fastcall_regs_ptr = NULL; |
Line 423... | Line 525... | ||
423 | } |
525 | } |
424 | param_index = 0; |
526 | param_index = 0; |
425 | 527 | ||
426 | ind += FUNC_PROLOG_SIZE; |
528 | ind += FUNC_PROLOG_SIZE; |
427 | func_sub_sp_offset = ind; |
529 | func_sub_sp_offset = ind; |
- | 530 | /* if the function returns a structure, then add an |
|
- | 531 | implicit pointer parameter */ |
|
- | 532 | func_vt = sym->type; |
|
- | 533 | func_var = (sym->c == FUNC_ELLIPSIS); |
|
- | 534 | #ifdef TCC_TARGET_PE |
|
428 | /* if the function returns a structure, then add an |
535 | size = type_size(&func_vt,&align); |
- | 536 | if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) { |
|
429 | implicit pointer parameter */ |
537 | #else |
430 | func_vt = sym->type; |
538 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
431 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
539 | #endif |
432 | /* XXX: fastcall case ? */ |
540 | /* XXX: fastcall case ? */ |
433 | func_vc = addr; |
541 | func_vc = addr; |
Line 447... | Line 555... | ||
447 | #endif |
555 | #endif |
448 | if (param_index < fastcall_nb_regs) { |
556 | if (param_index < fastcall_nb_regs) { |
449 | /* save FASTCALL register */ |
557 | /* save FASTCALL register */ |
450 | loc -= 4; |
558 | loc -= 4; |
451 | o(0x89); /* movl */ |
559 | o(0x89); /* movl */ |
452 | gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc); |
560 | gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc); |
453 | param_addr = loc; |
561 | param_addr = loc; |
454 | } else { |
562 | } else { |
455 | param_addr = addr; |
563 | param_addr = addr; |
456 | addr += size; |
564 | addr += size; |
457 | } |
565 | } |
458 | sym_push(sym->v & ~SYM_FIELD, type, |
566 | sym_push(sym->v & ~SYM_FIELD, type, |
459 | VT_LOCAL | VT_LVAL, param_addr); |
567 | VT_LOCAL | lvalue_type(type->t), param_addr); |
460 | param_index++; |
568 | param_index++; |
461 | } |
569 | } |
462 | func_ret_sub = 0; |
570 | func_ret_sub = 0; |
463 | /* pascal type call ? */ |
571 | /* pascal type call ? */ |
464 | if (func_call == FUNC_STDCALL) |
572 | if (func_call == FUNC_STDCALL) |
465 | func_ret_sub = addr - 8; |
573 | func_ret_sub = addr - 8; |
- | 574 | #ifndef TCC_TARGET_PE |
|
- | 575 | else if (func_vc) |
|
- | 576 | func_ret_sub = 4; |
|
- | 577 | #endif |
|
Line -... | Line 578... | ||
- | 578 | ||
466 | 579 | #ifdef CONFIG_TCC_BCHECK |
|
467 | /* leave some room for bound checking code */ |
580 | /* leave some room for bound checking code */ |
468 | if (do_bounds_check) { |
581 | if (tcc_state->do_bounds_check) { |
469 | oad(0xb8, 0); /* lbound section pointer */ |
582 | oad(0xb8, 0); /* lbound section pointer */ |
470 | oad(0xb8, 0); /* call to function */ |
583 | oad(0xb8, 0); /* call to function */ |
471 | func_bound_offset = lbounds_section->data_offset; |
584 | func_bound_offset = lbounds_section->data_offset; |
- | 585 | } |
|
472 | } |
586 | #endif |
Line 473... | Line 587... | ||
473 | } |
587 | } |
474 | 588 | ||
475 | /* generate function epilog */ |
589 | /* generate function epilog */ |
476 | void gfunc_epilog(void) |
590 | ST_FUNC void gfunc_epilog(void) |
Line 477... | Line 591... | ||
477 | { |
591 | { |
- | 592 | addr_t v, saved_ind; |
|
478 | int v, saved_ind; |
593 | |
479 | 594 | #ifdef CONFIG_TCC_BCHECK |
|
480 | #ifdef CONFIG_TCC_BCHECK |
595 | if (tcc_state->do_bounds_check |
481 | if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) { |
596 | && func_bound_offset != lbounds_section->data_offset) { |
482 | int saved_ind; |
597 | addr_t saved_ind; |
483 | int *bounds_ptr; |
598 | addr_t *bounds_ptr; |
484 | Sym *sym, *sym_data; |
599 | Sym *sym_data; |
485 | /* add end of table info */ |
600 | /* add end of table info */ |
486 | bounds_ptr = section_ptr_add(lbounds_section, sizeof(int)); |
601 | bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); |
487 | *bounds_ptr = 0; |
602 | *bounds_ptr = 0; |
488 | /* generate bound local allocation */ |
603 | /* generate bound local allocation */ |
489 | saved_ind = ind; |
604 | saved_ind = ind; |
490 | ind = func_sub_sp_offset; |
605 | ind = func_sub_sp_offset; |
491 | sym_data = get_sym_ref(&char_pointer_type, lbounds_section, |
606 | sym_data = get_sym_ref(&char_pointer_type, lbounds_section, |
492 | func_bound_offset, lbounds_section->data_offset); |
607 | func_bound_offset, lbounds_section->data_offset); |
493 | greloc(cur_text_section, sym_data, |
608 | greloc(cur_text_section, sym_data, |
494 | ind + 1, R_386_32); |
- | |
495 | oad(0xb8, 0); /* mov %eax, xxx */ |
- | |
496 | sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0); |
- | |
- | 609 | ind + 1, R_386_32); |
|
497 | greloc(cur_text_section, sym, |
610 | oad(0xb8, 0); /* mov %eax, xxx */ |
498 | ind + 1, R_386_PC32); |
611 | gen_static_call(TOK___bound_local_new); |
499 | oad(0xe8, -4); |
612 | |
500 | ind = saved_ind; |
613 | ind = saved_ind; |
501 | /* generate bound check local freeing */ |
614 | /* generate bound check local freeing */ |
502 | o(0x5250); /* save returned value, if any */ |
615 | o(0x5250); /* save returned value, if any */ |
503 | greloc(cur_text_section, sym_data, |
616 | greloc(cur_text_section, sym_data, |
504 | ind + 1, R_386_32); |
- | |
505 | oad(0xb8, 0); /* mov %eax, xxx */ |
- | |
506 | sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0); |
- | |
- | 617 | ind + 1, R_386_32); |
|
507 | greloc(cur_text_section, sym, |
618 | oad(0xb8, 0); /* mov %eax, xxx */ |
508 | ind + 1, R_386_PC32); |
619 | gen_static_call(TOK___bound_local_delete); |
509 | oad(0xe8, -4); |
620 | |
510 | o(0x585a); /* restore returned value, if any */ |
621 | o(0x585a); /* restore returned value, if any */ |
511 | } |
622 | } |
Line 523... | Line 634... | ||
523 | v = (-loc + 3) & -4; |
634 | v = (-loc + 3) & -4; |
524 | saved_ind = ind; |
635 | saved_ind = ind; |
525 | ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
636 | ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; |
526 | #ifdef TCC_TARGET_PE |
637 | #ifdef TCC_TARGET_PE |
527 | if (v >= 4096) { |
638 | if (v >= 4096) { |
528 | Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); |
- | |
529 | oad(0xb8, v); /* mov stacksize, %eax */ |
639 | oad(0xb8, v); /* mov stacksize, %eax */ |
530 | oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */ |
640 | gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */ |
531 | greloc(cur_text_section, sym, ind-4, R_386_PC32); |
- | |
532 | } else |
641 | } else |
533 | #endif |
642 | #endif |
534 | { |
643 | { |
535 | o(0xe58955); /* push %ebp, mov %esp, %ebp */ |
644 | o(0xe58955); /* push %ebp, mov %esp, %ebp */ |
536 | o(0xec81); /* sub esp, stacksize */ |
645 | o(0xec81); /* sub esp, stacksize */ |
Line 541... | Line 650... | ||
541 | } |
650 | } |
542 | ind = saved_ind; |
651 | ind = saved_ind; |
543 | } |
652 | } |
Line 544... | Line 653... | ||
544 | 653 | ||
545 | /* generate a jump to a label */ |
654 | /* generate a jump to a label */ |
546 | int gjmp(int t) |
655 | ST_FUNC int gjmp(int t) |
547 | { |
656 | { |
548 | return psym(0xe9, t); |
657 | return psym(0xe9, t); |
Line 549... | Line 658... | ||
549 | } |
658 | } |
550 | 659 | ||
551 | /* generate a jump to a fixed address */ |
660 | /* generate a jump to a fixed address */ |
552 | void gjmp_addr(int a) |
661 | ST_FUNC void gjmp_addr(int a) |
553 | { |
662 | { |
554 | int r; |
663 | int r; |
555 | r = a - ind - 2; |
664 | r = a - ind - 2; |
Line 560... | Line 669... | ||
560 | oad(0xe9, a - ind - 5); |
669 | oad(0xe9, a - ind - 5); |
561 | } |
670 | } |
562 | } |
671 | } |
Line 563... | Line 672... | ||
563 | 672 | ||
564 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
673 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
565 | int gtst(int inv, int t) |
674 | ST_FUNC int gtst(int inv, int t) |
566 | { |
- | |
567 | int v, *p; |
- | |
568 | 675 | { |
|
569 | v = vtop->r & VT_VALMASK; |
676 | int v = vtop->r & VT_VALMASK; |
570 | if (v == VT_CMP) { |
677 | if (v == VT_CMP) { |
571 | /* fast case : can jump directly since flags are set */ |
678 | /* fast case : can jump directly since flags are set */ |
572 | g(0x0f); |
679 | g(0x0f); |
573 | t = psym((vtop->c.i - 16) ^ inv, t); |
680 | t = psym((vtop->c.i - 16) ^ inv, t); |
574 | } else if (v == VT_JMP || v == VT_JMPI) { |
681 | } else if (v == VT_JMP || v == VT_JMPI) { |
575 | /* && or || optimization */ |
682 | /* && or || optimization */ |
576 | if ((v & 1) == inv) { |
683 | if ((v & 1) == inv) { |
577 | /* insert vtop->c jump list in t */ |
684 | /* insert vtop->c jump list in t */ |
578 | p = &vtop->c.i; |
685 | uint32_t n1, n = vtop->c.i; |
579 | while (*p != 0) |
686 | if (n) { |
580 | p = (int *)(cur_text_section->data + *p); |
687 | while ((n1 = read32le(cur_text_section->data + n))) |
- | 688 | n = n1; |
|
581 | *p = t; |
689 | write32le(cur_text_section->data + n, t); |
582 | t = vtop->c.i; |
- | |
583 | } else { |
- | |
584 | t = gjmp(t); |
- | |
585 | gsym(vtop->c.i); |
690 | t = vtop->c.i; |
586 | } |
691 | } |
587 | } else { |
- | |
588 | if (is_float(vtop->type.t)) { |
- | |
589 | vpushi(0); |
- | |
590 | gen_op(TOK_NE); |
- | |
591 | } |
- | |
592 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
- | |
593 | /* constant jmp optimization */ |
- | |
594 | if ((vtop->c.i != 0) != inv) |
692 | } else { |
595 | t = gjmp(t); |
- | |
596 | } else { |
693 | t = gjmp(t); |
597 | v = gv(RC_INT); |
- | |
598 | o(0x85); |
- | |
599 | o(0xc0 + v * 9); |
- | |
600 | g(0x0f); |
- | |
601 | t = psym(0x85 ^ inv, t); |
694 | gsym(vtop->c.i); |
602 | } |
695 | } |
603 | } |
696 | } |
604 | vtop--; |
697 | vtop--; |
605 | return t; |
698 | return t; |
Line 606... | Line 699... | ||
606 | } |
699 | } |
607 | 700 | ||
608 | /* generate an integer binary operation */ |
701 | /* generate an integer binary operation */ |
609 | void gen_opi(int op) |
702 | ST_FUNC void gen_opi(int op) |
Line 610... | Line 703... | ||
610 | { |
703 | { |
611 | int r, fr, opc, c; |
704 | int r, fr, opc, c; |
Line 620... | Line 713... | ||
620 | vswap(); |
713 | vswap(); |
621 | r = gv(RC_INT); |
714 | r = gv(RC_INT); |
622 | vswap(); |
715 | vswap(); |
623 | c = vtop->c.i; |
716 | c = vtop->c.i; |
624 | if (c == (char)c) { |
717 | if (c == (char)c) { |
625 | /* XXX: generate inc and dec for smaller code ? */ |
718 | /* generate inc and dec for smaller code */ |
- | 719 | if (c==1 && opc==0) { |
|
- | 720 | o (0x40 | r); // inc |
|
- | 721 | } else if (c==1 && opc==5) { |
|
- | 722 | o (0x48 | r); // dec |
|
- | 723 | } else { |
|
626 | o(0x83); |
724 | o(0x83); |
627 | o(0xc0 | (opc << 3) | r); |
725 | o(0xc0 | (opc << 3) | r); |
628 | g(c); |
726 | g(c); |
- | 727 | } |
|
629 | } else { |
728 | } else { |
630 | o(0x81); |
729 | o(0x81); |
631 | oad(0xc0 | (opc << 3) | r, c); |
730 | oad(0xc0 | (opc << 3) | r, c); |
632 | } |
731 | } |
633 | } else { |
732 | } else { |
Line 738... | Line 837... | ||
738 | } |
837 | } |
Line 739... | Line 838... | ||
739 | 838 | ||
740 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
839 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
741 | two operands are guaranted to have the same floating point type */ |
840 | two operands are guaranted to have the same floating point type */ |
742 | /* XXX: need to use ST1 too */ |
841 | /* XXX: need to use ST1 too */ |
743 | void gen_opf(int op) |
842 | ST_FUNC void gen_opf(int op) |
744 | { |
843 | { |
Line 745... | Line 844... | ||
745 | int a, ft, fc, swapped, r; |
844 | int a, ft, fc, swapped, r; |
746 | 845 | ||
Line 775... | Line 874... | ||
775 | swapped = !swapped; |
874 | swapped = !swapped; |
776 | else if (op == TOK_EQ || op == TOK_NE) |
875 | else if (op == TOK_EQ || op == TOK_NE) |
777 | swapped = 0; |
876 | swapped = 0; |
778 | if (swapped) |
877 | if (swapped) |
779 | o(0xc9d9); /* fxch %st(1) */ |
878 | o(0xc9d9); /* fxch %st(1) */ |
- | 879 | if (op == TOK_EQ || op == TOK_NE) |
|
780 | o(0xe9da); /* fucompp */ |
880 | o(0xe9da); /* fucompp */ |
- | 881 | else |
|
- | 882 | o(0xd9de); /* fcompp */ |
|
781 | o(0xe0df); /* fnstsw %ax */ |
883 | o(0xe0df); /* fnstsw %ax */ |
782 | if (op == TOK_EQ) { |
884 | if (op == TOK_EQ) { |
783 | o(0x45e480); /* and $0x45, %ah */ |
885 | o(0x45e480); /* and $0x45, %ah */ |
784 | o(0x40fC80); /* cmp $0x40, %ah */ |
886 | o(0x40fC80); /* cmp $0x40, %ah */ |
785 | } else if (op == TOK_NE) { |
887 | } else if (op == TOK_NE) { |
Line 821... | Line 923... | ||
821 | if (swapped) |
923 | if (swapped) |
822 | a++; |
924 | a++; |
823 | break; |
925 | break; |
824 | } |
926 | } |
825 | ft = vtop->type.t; |
927 | ft = vtop->type.t; |
826 | fc = vtop->c.ul; |
928 | fc = vtop->c.i; |
827 | if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
929 | if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
828 | o(0xde); /* fxxxp %st, %st(1) */ |
930 | o(0xde); /* fxxxp %st, %st(1) */ |
829 | o(0xc1 + (a << 3)); |
931 | o(0xc1 + (a << 3)); |
830 | } else { |
932 | } else { |
831 | /* if saved lvalue, then we must reload it */ |
933 | /* if saved lvalue, then we must reload it */ |
Line 833... | Line 935... | ||
833 | if ((r & VT_VALMASK) == VT_LLOCAL) { |
935 | if ((r & VT_VALMASK) == VT_LLOCAL) { |
834 | SValue v1; |
936 | SValue v1; |
835 | r = get_reg(RC_INT); |
937 | r = get_reg(RC_INT); |
836 | v1.type.t = VT_INT; |
938 | v1.type.t = VT_INT; |
837 | v1.r = VT_LOCAL | VT_LVAL; |
939 | v1.r = VT_LOCAL | VT_LVAL; |
838 | v1.c.ul = fc; |
940 | v1.c.i = fc; |
839 | load(r, &v1); |
941 | load(r, &v1); |
840 | fc = 0; |
942 | fc = 0; |
841 | } |
943 | } |
Line 842... | Line 944... | ||
842 | 944 | ||
Line 850... | Line 952... | ||
850 | } |
952 | } |
851 | } |
953 | } |
Line 852... | Line 954... | ||
852 | 954 | ||
853 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
955 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
854 | and 'long long' cases. */ |
956 | and 'long long' cases. */ |
855 | void gen_cvt_itof(int t) |
957 | ST_FUNC void gen_cvt_itof(int t) |
856 | { |
958 | { |
857 | save_reg(TREG_ST0); |
959 | save_reg(TREG_ST0); |
858 | gv(RC_INT); |
960 | gv(RC_INT); |
859 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
961 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
Line 879... | Line 981... | ||
879 | } |
981 | } |
880 | vtop->r = TREG_ST0; |
982 | vtop->r = TREG_ST0; |
881 | } |
983 | } |
Line 882... | Line 984... | ||
882 | 984 | ||
883 | /* convert fp to int 't' type */ |
- | |
884 | /* XXX: handle long long case */ |
985 | /* convert fp to int 't' type */ |
885 | void gen_cvt_ftoi(int t) |
986 | ST_FUNC void gen_cvt_ftoi(int t) |
886 | { |
- | |
887 | int r, r2, size; |
- | |
888 | Sym *sym; |
987 | { |
889 | CType ushort_type; |
- | |
890 | 988 | #ifndef COMMIT_4ad186c5ef61_IS_FIXED |
|
891 | ushort_type.t = VT_SHORT | VT_UNSIGNED; |
- | |
892 | 989 | /* a good version but it takes a more time to execute */ |
|
893 | gv(RC_FLOAT); |
990 | gv(RC_FLOAT); |
894 | if (t != VT_INT) |
991 | save_reg(TREG_EAX); |
895 | size = 8; |
- | |
896 | else |
- | |
897 | size = 4; |
- | |
898 | - | ||
899 | o(0x2dd9); /* ldcw xxx */ |
992 | save_reg(TREG_EDX); |
900 | sym = external_global_sym(TOK___tcc_int_fpu_control, |
- | |
901 | &ushort_type, VT_LVAL); |
- | |
902 | greloc(cur_text_section, sym, |
- | |
903 | ind, R_386_32); |
- | |
904 | gen_le32(0); |
- | |
905 | 993 | gen_static_call(TOK___tcc_cvt_ftol); |
|
906 | oad(0xec81, size); /* sub $xxx, %esp */ |
994 | vtop->r = TREG_EAX; /* mark reg as used */ |
907 | if (size == 4) |
995 | if (t == VT_LLONG) |
908 | o(0x1cdb); /* fistpl */ |
996 | vtop->r2 = TREG_EDX; |
909 | else |
997 | #else |
910 | o(0x3cdf); /* fistpll */ |
998 | /* a new version with a bug: t2a = 44100312 */ |
911 | o(0x24); |
- | |
912 | o(0x2dd9); /* ldcw xxx */ |
- | |
913 | sym = external_global_sym(TOK___tcc_fpu_control, |
- | |
914 | &ushort_type, VT_LVAL); |
999 | /* |
915 | greloc(cur_text_section, sym, |
- | |
916 | ind, R_386_32); |
1000 | #include |
917 | gen_le32(0); |
- | |
918 | 1001 | int main() { |
|
919 | r = get_reg(RC_INT); |
- | |
920 | o(0x58 + r); /* pop r */ |
1002 | int t1 = 176401255; |
921 | if (size == 8) { |
- | |
922 | if (t == VT_LLONG) { |
1003 | float f = 0.25f; |
923 | vtop->r = r; /* mark reg as used */ |
1004 | int t2a = (int)(t1 * f); // must be 44100313 |
924 | r2 = get_reg(RC_INT); |
1005 | int t2b = (int)(t1 * (float)0.25f); |
925 | o(0x58 + r2); /* pop r2 */ |
- | |
926 | vtop->r2 = r2; |
- | |
927 | } else { |
- | |
928 | o(0x04c483); /* add $4, %esp */ |
1006 | printf("t2a=%d t2b=%d \n",t2a,t2b); |
929 | } |
1007 | return 0; |
- | 1008 | } |
|
- | 1009 | */ |
|
- | 1010 | int bt = vtop->type.t & VT_BTYPE; |
|
- | 1011 | if (bt == VT_FLOAT) |
|
- | 1012 | vpush_global_sym(&func_old_type, TOK___fixsfdi); |
|
- | 1013 | else if (bt == VT_LDOUBLE) |
|
- | 1014 | vpush_global_sym(&func_old_type, TOK___fixxfdi); |
|
- | 1015 | else |
|
- | 1016 | vpush_global_sym(&func_old_type, TOK___fixdfdi); |
|
- | 1017 | vswap(); |
|
- | 1018 | gfunc_call(1); |
|
930 | } |
1019 | vpushi(0); |
- | 1020 | vtop->r = REG_IRET; |
|
- | 1021 | vtop->r2 = REG_LRET; |
|
931 | vtop->r = r; |
1022 | #endif |
Line 932... | Line 1023... | ||
932 | } |
1023 | } |
933 | 1024 | ||
934 | /* convert from one floating point type to another */ |
1025 | /* convert from one floating point type to another */ |
935 | void gen_cvt_ftof(int t) |
1026 | ST_FUNC void gen_cvt_ftof(int t) |
936 | { |
1027 | { |
937 | /* all we have to do on i386 is to put the float in a register */ |
1028 | /* all we have to do on i386 is to put the float in a register */ |
Line 938... | Line 1029... | ||
938 | gv(RC_FLOAT); |
1029 | gv(RC_FLOAT); |
939 | } |
1030 | } |
940 | 1031 | ||
941 | /* computed goto support */ |
1032 | /* computed goto support */ |
942 | void ggoto(void) |
1033 | ST_FUNC void ggoto(void) |
943 | { |
1034 | { |
Line 944... | Line 1035... | ||
944 | gcall_or_jmp(1); |
1035 | gcall_or_jmp(1); |
945 | vtop--; |
1036 | vtop--; |
Line 946... | Line 1037... | ||
946 | } |
1037 | } |
947 | 1038 | ||
948 | /* bound check support functions */ |
1039 | /* bound check support functions */ |
949 | #ifdef CONFIG_TCC_BCHECK |
- | |
950 | - | ||
951 | /* generate a bounded pointer addition */ |
1040 | #ifdef CONFIG_TCC_BCHECK |
952 | void gen_bounded_ptr_add(void) |
1041 | |
953 | { |
1042 | /* generate a bounded pointer addition */ |
954 | Sym *sym; |
1043 | ST_FUNC void gen_bounded_ptr_add(void) |
955 | 1044 | { |
|
956 | /* prepare fast i386 function call (args in eax and edx) */ |
1045 | /* prepare fast i386 function call (args in eax and edx) */ |
957 | gv2(RC_EAX, RC_EDX); |
1046 | gv2(RC_EAX, RC_EDX); |
958 | /* save all temporary registers */ |
- | |
959 | vtop -= 2; |
- | |
960 | save_regs(0); |
- | |
961 | /* do a fast function call */ |
1047 | /* save all temporary registers */ |
962 | sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0); |
1048 | vtop -= 2; |
963 | greloc(cur_text_section, sym, |
1049 | save_regs(0); |
964 | ind + 1, R_386_PC32); |
1050 | /* do a fast function call */ |
965 | oad(0xe8, -4); |
1051 | gen_static_call(TOK___bound_ptr_add); |
966 | /* returned pointer is in eax */ |
1052 | /* returned pointer is in eax */ |
Line 967... | Line 1053... | ||
967 | vtop++; |
1053 | vtop++; |
968 | vtop->r = TREG_EAX | VT_BOUNDED; |
1054 | vtop->r = TREG_EAX | VT_BOUNDED; |
969 | /* address of bounding function call point */ |
1055 | /* address of bounding function call point */ |
970 | vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); |
1056 | vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel)); |
971 | } |
1057 | } |
972 | 1058 | ||
973 | /* patch pointer addition in vtop so that pointer dereferencing is |
1059 | /* patch pointer addition in vtop so that pointer dereferencing is |
974 | also tested */ |
1060 | also tested */ |
Line 975... | Line 1061... | ||
975 | void gen_bounded_ptr_deref(void) |
1061 | ST_FUNC void gen_bounded_ptr_deref(void) |
Line 995... | Line 1081... | ||
995 | case 4: func = TOK___bound_ptr_indir4; break; |
1081 | case 4: func = TOK___bound_ptr_indir4; break; |
996 | case 8: func = TOK___bound_ptr_indir8; break; |
1082 | case 8: func = TOK___bound_ptr_indir8; break; |
997 | case 12: func = TOK___bound_ptr_indir12; break; |
1083 | case 12: func = TOK___bound_ptr_indir12; break; |
998 | case 16: func = TOK___bound_ptr_indir16; break; |
1084 | case 16: func = TOK___bound_ptr_indir16; break; |
999 | default: |
1085 | default: |
1000 | error("unhandled size when derefencing bounded pointer"); |
1086 | tcc_error("unhandled size when dereferencing bounded pointer"); |
1001 | func = 0; |
1087 | func = 0; |
1002 | break; |
1088 | break; |
1003 | } |
1089 | } |
Line 1004... | Line 1090... | ||
1004 | 1090 | ||
1005 | /* patch relocation */ |
1091 | /* patch relocation */ |
1006 | /* XXX: find a better solution ? */ |
1092 | /* XXX: find a better solution ? */ |
1007 | rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul); |
1093 | rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i); |
1008 | sym = external_global_sym(func, &func_old_type, 0); |
1094 | sym = external_global_sym(func, &func_old_type, 0); |
1009 | if (!sym->c) |
1095 | if (!sym->c) |
1010 | put_extern_sym(sym, NULL, 0, 0); |
1096 | put_extern_sym(sym, NULL, 0, 0); |
1011 | rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); |
1097 | rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info)); |
1012 | } |
1098 | } |
Line -... | Line 1099... | ||
- | 1099 | #endif |
|
- | 1100 | ||
- | 1101 | /* Save the stack pointer onto the stack */ |
|
- | 1102 | ST_FUNC void gen_vla_sp_save(int addr) { |
|
- | 1103 | /* mov %esp,addr(%ebp)*/ |
|
- | 1104 | o(0x89); |
|
- | 1105 | gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); |
|
- | 1106 | } |
|
- | 1107 | ||
- | 1108 | /* Restore the SP from a location on the stack */ |
|
- | 1109 | ST_FUNC void gen_vla_sp_restore(int addr) { |
|
- | 1110 | o(0x8b); |
|
- | 1111 | gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr); |
|
- | 1112 | } |
|
- | 1113 | ||
- | 1114 | /* Subtract from the stack pointer, and push the resulting value onto the stack */ |
|
- | 1115 | ST_FUNC void gen_vla_alloc(CType *type, int align) { |
|
- | 1116 | #ifdef TCC_TARGET_PE |
|
- | 1117 | /* alloca does more than just adjust %rsp on Windows */ |
|
- | 1118 | vpush_global_sym(&func_old_type, TOK_alloca); |
|
- | 1119 | vswap(); /* Move alloca ref past allocation size */ |
|
- | 1120 | gfunc_call(1); |
|
- | 1121 | #else |
|
- | 1122 | int r; |
|
- | 1123 | r = gv(RC_INT); /* allocation size */ |
|
- | 1124 | /* sub r,%rsp */ |
|
- | 1125 | o(0x2b); |
|
- | 1126 | o(0xe0 | r); |
|
- | 1127 | /* We align to 16 bytes rather than align */ |
|
- | 1128 | /* and ~15, %esp */ |
|
- | 1129 | o(0xf0e483); |
|
- | 1130 | vpop(); |
|
- | 1131 | #endif |
|
1013 | #endif |
1132 | } |
1014 | 1133 | ||
1015 | /* end of X86 code generator */ |
1134 | /* end of X86 code generator */ |
- | 1135 | /*************************************************************/ |