Rev 647 | 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 | #include "tcc.h" |
|
- | 22 | #ifdef CONFIG_TCC_ASM |
|
20 | 23 | ||
21 | static int asm_get_local_label_name(TCCState *s1, unsigned int n) |
24 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
22 | { |
25 | { |
23 | char buf[64]; |
26 | char buf[64]; |
Line 24... | Line 27... | ||
24 | TokenSym *ts; |
27 | TokenSym *ts; |
25 | 28 | ||
26 | snprintf(buf, sizeof(buf), "L..%u", n); |
29 | snprintf(buf, sizeof(buf), "L..%u", n); |
27 | ts = tok_alloc(buf, strlen(buf)); |
30 | ts = tok_alloc(buf, strlen(buf)); |
Line 28... | Line 31... | ||
28 | return ts->tok; |
31 | return ts->tok; |
- | 32 | } |
|
- | 33 | ||
Line 29... | Line 34... | ||
29 | } |
34 | ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); |
30 | 35 | static int tcc_assemble_internal(TCCState *s1, int do_preprocess); |
|
Line 31... | Line 36... | ||
31 | static void asm_expr(TCCState *s1, ExprValue *pe); |
36 | static Sym sym_dot; |
Line 39... | Line 44... | ||
39 | int op, n, label; |
44 | int op, n, label; |
40 | const char *p; |
45 | const char *p; |
Line 41... | Line 46... | ||
41 | 46 | ||
42 | switch(tok) { |
47 | switch(tok) { |
43 | case TOK_PPNUM: |
48 | case TOK_PPNUM: |
44 | p = tokc.cstr->data; |
49 | p = tokc.str.data; |
45 | n = strtoul(p, (char **)&p, 0); |
50 | n = strtoul(p, (char **)&p, 0); |
46 | if (*p == 'b' || *p == 'f') { |
51 | if (*p == 'b' || *p == 'f') { |
47 | /* backward or forward label */ |
52 | /* backward or forward label */ |
48 | label = asm_get_local_label_name(s1, n); |
53 | label = asm_get_local_label_name(s1, n); |
49 | sym = label_find(label); |
54 | sym = label_find(label); |
50 | if (*p == 'b') { |
55 | if (*p == 'b') { |
51 | /* backward : find the last corresponding defined label */ |
56 | /* backward : find the last corresponding defined label */ |
52 | if (sym && sym->r == 0) |
57 | if (sym && sym->r == 0) |
53 | sym = sym->prev_tok; |
58 | sym = sym->prev_tok; |
54 | if (!sym) |
59 | if (!sym) |
55 | error("local label '%d' not found backward", n); |
60 | tcc_error("local label '%d' not found backward", n); |
56 | } else { |
61 | } else { |
57 | /* forward */ |
62 | /* forward */ |
58 | if (!sym || sym->r) { |
63 | if (!sym || sym->r) { |
59 | /* if the last label is defined, then define a new one */ |
64 | /* if the last label is defined, then define a new one */ |
Line 65... | Line 70... | ||
65 | pe->sym = sym; |
70 | pe->sym = sym; |
66 | } else if (*p == '\0') { |
71 | } else if (*p == '\0') { |
67 | pe->v = n; |
72 | pe->v = n; |
68 | pe->sym = NULL; |
73 | pe->sym = NULL; |
69 | } else { |
74 | } else { |
70 | error("invalid number syntax"); |
75 | tcc_error("invalid number syntax"); |
71 | } |
76 | } |
72 | next(); |
77 | next(); |
73 | break; |
78 | break; |
74 | case '+': |
79 | case '+': |
75 | next(); |
80 | next(); |
Line 79... | Line 84... | ||
79 | case '~': |
84 | case '~': |
80 | op = tok; |
85 | op = tok; |
81 | next(); |
86 | next(); |
82 | asm_expr_unary(s1, pe); |
87 | asm_expr_unary(s1, pe); |
83 | if (pe->sym) |
88 | if (pe->sym) |
84 | error("invalid operation with label"); |
89 | tcc_error("invalid operation with label"); |
85 | if (op == '-') |
90 | if (op == '-') |
86 | pe->v = -pe->v; |
91 | pe->v = -pe->v; |
87 | else |
92 | else |
88 | pe->v = ~pe->v; |
93 | pe->v = ~pe->v; |
89 | break; |
94 | break; |
Line 96... | Line 101... | ||
96 | case '(': |
101 | case '(': |
97 | next(); |
102 | next(); |
98 | asm_expr(s1, pe); |
103 | asm_expr(s1, pe); |
99 | skip(')'); |
104 | skip(')'); |
100 | break; |
105 | break; |
- | 106 | case '.': |
|
- | 107 | pe->v = 0; |
|
- | 108 | pe->sym = &sym_dot; |
|
- | 109 | sym_dot.type.t = VT_VOID | VT_STATIC; |
|
- | 110 | sym_dot.r = cur_text_section->sh_num; |
|
- | 111 | sym_dot.jnext = ind; |
|
- | 112 | next(); |
|
- | 113 | break; |
|
101 | default: |
114 | default: |
102 | if (tok >= TOK_IDENT) { |
115 | if (tok >= TOK_IDENT) { |
103 | /* label case : if the label was not found, add one */ |
116 | /* label case : if the label was not found, add one */ |
104 | sym = label_find(tok); |
117 | sym = label_find(tok); |
105 | if (!sym) { |
118 | if (!sym) { |
Line 107... | Line 120... | ||
107 | /* NOTE: by default, the symbol is global */ |
120 | /* NOTE: by default, the symbol is global */ |
108 | sym->type.t = VT_VOID; |
121 | sym->type.t = VT_VOID; |
109 | } |
122 | } |
110 | if (sym->r == SHN_ABS) { |
123 | if (sym->r == SHN_ABS) { |
111 | /* if absolute symbol, no need to put a symbol value */ |
124 | /* if absolute symbol, no need to put a symbol value */ |
112 | pe->v = (long)sym->next; |
125 | pe->v = sym->jnext; |
113 | pe->sym = NULL; |
126 | pe->sym = NULL; |
114 | } else { |
127 | } else { |
115 | pe->v = 0; |
128 | pe->v = 0; |
116 | pe->sym = sym; |
129 | pe->sym = sym; |
117 | } |
130 | } |
118 | next(); |
131 | next(); |
119 | } else { |
132 | } else { |
120 | error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); |
133 | tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); |
121 | } |
134 | } |
122 | break; |
135 | break; |
123 | } |
136 | } |
124 | } |
137 | } |
Line 135... | Line 148... | ||
135 | op != TOK_SHL && op != TOK_SAR) |
148 | op != TOK_SHL && op != TOK_SAR) |
136 | break; |
149 | break; |
137 | next(); |
150 | next(); |
138 | asm_expr_unary(s1, &e2); |
151 | asm_expr_unary(s1, &e2); |
139 | if (pe->sym || e2.sym) |
152 | if (pe->sym || e2.sym) |
140 | error("invalid operation with label"); |
153 | tcc_error("invalid operation with label"); |
141 | switch(op) { |
154 | switch(op) { |
142 | case '*': |
155 | case '*': |
143 | pe->v *= e2.v; |
156 | pe->v *= e2.v; |
144 | break; |
157 | break; |
145 | case '/': |
158 | case '/': |
146 | if (e2.v == 0) { |
159 | if (e2.v == 0) { |
147 | div_error: |
160 | div_error: |
148 | error("division by zero"); |
161 | tcc_error("division by zero"); |
149 | } |
162 | } |
150 | pe->v /= e2.v; |
163 | pe->v /= e2.v; |
151 | break; |
164 | break; |
152 | case '%': |
165 | case '%': |
153 | if (e2.v == 0) |
166 | if (e2.v == 0) |
Line 176... | Line 189... | ||
176 | if (op != '&' && op != '|' && op != '^') |
189 | if (op != '&' && op != '|' && op != '^') |
177 | break; |
190 | break; |
178 | next(); |
191 | next(); |
179 | asm_expr_prod(s1, &e2); |
192 | asm_expr_prod(s1, &e2); |
180 | if (pe->sym || e2.sym) |
193 | if (pe->sym || e2.sym) |
181 | error("invalid operation with label"); |
194 | tcc_error("invalid operation with label"); |
182 | switch(op) { |
195 | switch(op) { |
183 | case '&': |
196 | case '&': |
184 | pe->v &= e2.v; |
197 | pe->v &= e2.v; |
185 | break; |
198 | break; |
186 | case '|': |
199 | case '|': |
Line 223... | Line 236... | ||
223 | } else if (pe->sym && e2.sym) { |
236 | } else if (pe->sym && e2.sym) { |
224 | if (pe->sym == e2.sym) { |
237 | if (pe->sym == e2.sym) { |
225 | /* OK */ |
238 | /* OK */ |
226 | } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) { |
239 | } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) { |
227 | /* we also accept defined symbols in the same section */ |
240 | /* we also accept defined symbols in the same section */ |
228 | pe->v += (long)pe->sym->next - (long)e2.sym->next; |
241 | pe->v += pe->sym->jnext - e2.sym->jnext; |
229 | } else { |
242 | } else { |
230 | goto cannot_relocate; |
243 | goto cannot_relocate; |
231 | } |
244 | } |
232 | pe->sym = NULL; /* same symbols can be substracted to NULL */ |
245 | pe->sym = NULL; /* same symbols can be subtracted to NULL */ |
233 | } else { |
246 | } else { |
234 | cannot_relocate: |
247 | cannot_relocate: |
235 | error("invalid operation with label"); |
248 | tcc_error("invalid operation with label"); |
236 | } |
249 | } |
237 | } |
250 | } |
238 | } |
251 | } |
239 | } |
252 | } |
Line 240... | Line 253... | ||
240 | 253 | ||
241 | static void asm_expr(TCCState *s1, ExprValue *pe) |
254 | ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe) |
242 | { |
255 | { |
243 | asm_expr_sum(s1, pe); |
256 | asm_expr_sum(s1, pe); |
Line 244... | Line 257... | ||
244 | } |
257 | } |
245 | 258 | ||
246 | static int asm_int_expr(TCCState *s1) |
259 | ST_FUNC int asm_int_expr(TCCState *s1) |
247 | { |
260 | { |
248 | ExprValue e; |
261 | ExprValue e; |
249 | asm_expr(s1, &e); |
262 | asm_expr(s1, &e); |
Line 262... | Line 275... | ||
262 | sym = label_find(label); |
275 | sym = label_find(label); |
263 | if (sym) { |
276 | if (sym) { |
264 | if (sym->r) { |
277 | if (sym->r) { |
265 | /* the label is already defined */ |
278 | /* the label is already defined */ |
266 | if (!is_local) { |
279 | if (!is_local) { |
267 | error("assembler label '%s' already defined", |
280 | tcc_error("assembler label '%s' already defined", |
268 | get_tok_str(label, NULL)); |
281 | get_tok_str(label, NULL)); |
269 | } else { |
282 | } else { |
270 | /* redefinition of local labels is possible */ |
283 | /* redefinition of local labels is possible */ |
271 | goto new_label; |
284 | goto new_label; |
272 | } |
285 | } |
Line 275... | Line 288... | ||
275 | new_label: |
288 | new_label: |
276 | sym = label_push(&s1->asm_labels, label, 0); |
289 | sym = label_push(&s1->asm_labels, label, 0); |
277 | sym->type.t = VT_STATIC | VT_VOID; |
290 | sym->type.t = VT_STATIC | VT_VOID; |
278 | } |
291 | } |
279 | sym->r = sh_num; |
292 | sym->r = sh_num; |
280 | sym->next = (void *)value; |
293 | sym->jnext = value; |
281 | } |
294 | } |
Line 282... | Line 295... | ||
282 | 295 | ||
283 | static void asm_new_label(TCCState *s1, int label, int is_local) |
296 | static void asm_new_label(TCCState *s1, int label, int is_local) |
284 | { |
297 | { |
Line 296... | Line 309... | ||
296 | if (s->r) { |
309 | if (s->r) { |
297 | if (s->r == SHN_ABS) |
310 | if (s->r == SHN_ABS) |
298 | sec = SECTION_ABS; |
311 | sec = SECTION_ABS; |
299 | else |
312 | else |
300 | sec = st->sections[s->r]; |
313 | sec = st->sections[s->r]; |
301 | put_extern_sym2(s, sec, (long)s->next, 0, 0); |
314 | put_extern_sym2(s, sec, s->jnext, 0, 0); |
302 | } |
315 | } |
303 | /* remove label */ |
316 | /* remove label */ |
304 | table_ident[s->v - TOK_IDENT]->sym_label = NULL; |
317 | table_ident[s->v - TOK_IDENT]->sym_label = NULL; |
305 | sym_free(s); |
318 | sym_free(s); |
306 | } |
319 | } |
Line 326... | Line 339... | ||
326 | int n, offset, v, size, tok1; |
339 | int n, offset, v, size, tok1; |
327 | Section *sec; |
340 | Section *sec; |
328 | uint8_t *ptr; |
341 | uint8_t *ptr; |
Line 329... | Line 342... | ||
329 | 342 | ||
330 | /* assembler directive */ |
- | |
331 | next(); |
343 | /* assembler directive */ |
332 | sec = cur_text_section; |
344 | sec = cur_text_section; |
333 | switch(tok) { |
345 | switch(tok) { |
- | 346 | case TOK_ASMDIR_align: |
|
334 | case TOK_ASM_align: |
347 | case TOK_ASMDIR_p2align: |
335 | case TOK_ASM_skip: |
348 | case TOK_ASMDIR_skip: |
336 | case TOK_ASM_space: |
349 | case TOK_ASMDIR_space: |
337 | tok1 = tok; |
350 | tok1 = tok; |
338 | next(); |
351 | next(); |
- | 352 | n = asm_int_expr(s1); |
|
- | 353 | if (tok1 == TOK_ASMDIR_p2align) |
|
- | 354 | { |
|
- | 355 | if (n < 0 || n > 30) |
|
- | 356 | tcc_error("invalid p2align, must be between 0 and 30"); |
|
- | 357 | n = 1 << n; |
|
- | 358 | tok1 = TOK_ASMDIR_align; |
|
339 | n = asm_int_expr(s1); |
359 | } |
340 | if (tok1 == TOK_ASM_align) { |
360 | if (tok1 == TOK_ASMDIR_align) { |
341 | if (n < 0 || (n & (n-1)) != 0) |
361 | if (n < 0 || (n & (n-1)) != 0) |
342 | error("alignment must be a positive power of two"); |
362 | tcc_error("alignment must be a positive power of two"); |
343 | offset = (ind + n - 1) & -n; |
363 | offset = (ind + n - 1) & -n; |
344 | size = offset - ind; |
364 | size = offset - ind; |
345 | /* the section must have a compatible alignment */ |
365 | /* the section must have a compatible alignment */ |
346 | if (sec->sh_addralign < n) |
366 | if (sec->sh_addralign < n) |
Line 359... | Line 379... | ||
359 | ptr = section_ptr_add(sec, size); |
379 | ptr = section_ptr_add(sec, size); |
360 | memset(ptr, v, size); |
380 | memset(ptr, v, size); |
361 | } |
381 | } |
362 | ind += size; |
382 | ind += size; |
363 | break; |
383 | break; |
364 | case TOK_ASM_quad: |
384 | case TOK_ASMDIR_quad: |
365 | next(); |
385 | next(); |
366 | for(;;) { |
386 | for(;;) { |
367 | uint64_t vl; |
387 | uint64_t vl; |
368 | const char *p; |
388 | const char *p; |
Line 369... | Line 389... | ||
369 | 389 | ||
370 | p = tokc.cstr->data; |
390 | p = tokc.str.data; |
371 | if (tok != TOK_PPNUM) { |
391 | if (tok != TOK_PPNUM) { |
372 | error_constant: |
392 | error_constant: |
373 | error("64 bit constant"); |
393 | tcc_error("64 bit constant"); |
374 | } |
394 | } |
375 | vl = strtoll(p, (char **)&p, 0); |
395 | vl = strtoll(p, (char **)&p, 0); |
376 | if (*p != '\0') |
396 | if (*p != '\0') |
377 | goto error_constant; |
397 | goto error_constant; |
Line 386... | Line 406... | ||
386 | if (tok != ',') |
406 | if (tok != ',') |
387 | break; |
407 | break; |
388 | next(); |
408 | next(); |
389 | } |
409 | } |
390 | break; |
410 | break; |
391 | case TOK_ASM_byte: |
411 | case TOK_ASMDIR_byte: |
392 | size = 1; |
412 | size = 1; |
393 | goto asm_data; |
413 | goto asm_data; |
394 | case TOK_ASM_word: |
414 | case TOK_ASMDIR_word: |
395 | case TOK_SHORT: |
415 | case TOK_ASMDIR_short: |
396 | size = 2; |
416 | size = 2; |
397 | goto asm_data; |
417 | goto asm_data; |
398 | case TOK_LONG: |
418 | case TOK_ASMDIR_long: |
399 | case TOK_INT: |
419 | case TOK_ASMDIR_int: |
400 | size = 4; |
420 | size = 4; |
401 | asm_data: |
421 | asm_data: |
402 | next(); |
422 | next(); |
403 | for(;;) { |
423 | for(;;) { |
404 | ExprValue e; |
424 | ExprValue e; |
Line 420... | Line 440... | ||
420 | if (tok != ',') |
440 | if (tok != ',') |
421 | break; |
441 | break; |
422 | next(); |
442 | next(); |
423 | } |
443 | } |
424 | break; |
444 | break; |
425 | case TOK_ASM_fill: |
445 | case TOK_ASMDIR_fill: |
426 | { |
446 | { |
427 | int repeat, size, val, i, j; |
447 | int repeat, size, val, i, j; |
428 | uint8_t repeat_buf[8]; |
448 | uint8_t repeat_buf[8]; |
429 | next(); |
449 | next(); |
430 | repeat = asm_int_expr(s1); |
450 | repeat = asm_int_expr(s1); |
431 | if (repeat < 0) { |
451 | if (repeat < 0) { |
432 | error("repeat < 0; .fill ignored"); |
452 | tcc_error("repeat < 0; .fill ignored"); |
433 | break; |
453 | break; |
434 | } |
454 | } |
435 | size = 1; |
455 | size = 1; |
436 | val = 0; |
456 | val = 0; |
437 | if (tok == ',') { |
457 | if (tok == ',') { |
438 | next(); |
458 | next(); |
439 | size = asm_int_expr(s1); |
459 | size = asm_int_expr(s1); |
440 | if (size < 0) { |
460 | if (size < 0) { |
441 | error("size < 0; .fill ignored"); |
461 | tcc_error("size < 0; .fill ignored"); |
442 | break; |
462 | break; |
443 | } |
463 | } |
444 | if (size > 8) |
464 | if (size > 8) |
445 | size = 8; |
465 | size = 8; |
446 | if (tok == ',') { |
466 | if (tok == ',') { |
Line 462... | Line 482... | ||
462 | g(repeat_buf[j]); |
482 | g(repeat_buf[j]); |
463 | } |
483 | } |
464 | } |
484 | } |
465 | } |
485 | } |
466 | break; |
486 | break; |
- | 487 | case TOK_ASMDIR_rept: |
|
- | 488 | { |
|
- | 489 | int repeat; |
|
- | 490 | TokenString init_str; |
|
- | 491 | ParseState saved_parse_state = {0}; |
|
- | 492 | next(); |
|
- | 493 | repeat = asm_int_expr(s1); |
|
- | 494 | tok_str_new(&init_str); |
|
- | 495 | next(); |
|
- | 496 | while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) { |
|
- | 497 | tok_str_add_tok(&init_str); |
|
- | 498 | next(); |
|
- | 499 | } |
|
- | 500 | if (tok == CH_EOF) tcc_error("we at end of file, .endr not found"); |
|
- | 501 | next(); |
|
- | 502 | tok_str_add(&init_str, -1); |
|
- | 503 | tok_str_add(&init_str, 0); |
|
- | 504 | save_parse_state(&saved_parse_state); |
|
- | 505 | begin_macro(&init_str, 0); |
|
- | 506 | while (repeat-- > 0) { |
|
- | 507 | tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS)); |
|
- | 508 | macro_ptr = init_str.str; |
|
- | 509 | } |
|
- | 510 | end_macro(); |
|
- | 511 | restore_parse_state(&saved_parse_state); |
|
- | 512 | break; |
|
- | 513 | } |
|
467 | case TOK_ASM_org: |
514 | case TOK_ASMDIR_org: |
468 | { |
515 | { |
469 | unsigned long n; |
516 | unsigned long n; |
470 | next(); |
517 | next(); |
471 | /* XXX: handle section symbols too */ |
518 | /* XXX: handle section symbols too */ |
472 | n = asm_int_expr(s1); |
519 | n = asm_int_expr(s1); |
473 | if (n < ind) |
520 | if (n < ind) |
474 | error("attempt to .org backwards"); |
521 | tcc_error("attempt to .org backwards"); |
475 | v = 0; |
522 | v = 0; |
476 | size = n - ind; |
523 | size = n - ind; |
477 | goto zero_pad; |
524 | goto zero_pad; |
478 | } |
525 | } |
479 | break; |
526 | break; |
480 | case TOK_ASM_globl: |
527 | case TOK_ASMDIR_globl: |
481 | case TOK_ASM_global: |
528 | case TOK_ASMDIR_global: |
- | 529 | case TOK_ASMDIR_weak: |
|
- | 530 | case TOK_ASMDIR_hidden: |
|
- | 531 | tok1 = tok; |
|
482 | { |
532 | do { |
483 | Sym *sym; |
533 | Sym *sym; |
Line 484... | Line 534... | ||
484 | 534 | ||
485 | next(); |
535 | next(); |
486 | sym = label_find(tok); |
536 | sym = label_find(tok); |
487 | if (!sym) { |
537 | if (!sym) { |
488 | sym = label_push(&s1->asm_labels, tok, 0); |
538 | sym = label_push(&s1->asm_labels, tok, 0); |
489 | sym->type.t = VT_VOID; |
539 | sym->type.t = VT_VOID; |
- | 540 | } |
|
490 | } |
541 | if (tok1 != TOK_ASMDIR_hidden) |
- | 542 | sym->type.t &= ~VT_STATIC; |
|
- | 543 | if (tok1 == TOK_ASMDIR_weak) |
|
- | 544 | sym->type.t |= VT_WEAK; |
|
- | 545 | else if (tok1 == TOK_ASMDIR_hidden) |
|
491 | sym->type.t &= ~VT_STATIC; |
546 | sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT; |
492 | next(); |
547 | next(); |
493 | } |
548 | } while (tok == ','); |
494 | break; |
549 | break; |
495 | case TOK_ASM_string: |
550 | case TOK_ASMDIR_string: |
496 | case TOK_ASM_ascii: |
551 | case TOK_ASMDIR_ascii: |
497 | case TOK_ASM_asciz: |
552 | case TOK_ASMDIR_asciz: |
498 | { |
553 | { |
499 | const uint8_t *p; |
554 | const uint8_t *p; |
Line 500... | Line 555... | ||
500 | int i, size, t; |
555 | int i, size, t; |
501 | 556 | ||
502 | t = tok; |
557 | t = tok; |
503 | next(); |
558 | next(); |
504 | for(;;) { |
559 | for(;;) { |
505 | if (tok != TOK_STR) |
560 | if (tok != TOK_STR) |
506 | expect("string constant"); |
561 | expect("string constant"); |
507 | p = tokc.cstr->data; |
562 | p = tokc.str.data; |
508 | size = tokc.cstr->size; |
563 | size = tokc.str.size; |
509 | if (t == TOK_ASM_ascii && size > 0) |
564 | if (t == TOK_ASMDIR_ascii && size > 0) |
510 | size--; |
565 | size--; |
511 | for(i = 0; i < size; i++) |
566 | for(i = 0; i < size; i++) |
512 | g(p[i]); |
567 | g(p[i]); |
Line 517... | Line 572... | ||
517 | break; |
572 | break; |
518 | } |
573 | } |
519 | } |
574 | } |
520 | } |
575 | } |
521 | break; |
576 | break; |
522 | case TOK_ASM_text: |
577 | case TOK_ASMDIR_text: |
523 | case TOK_ASM_data: |
578 | case TOK_ASMDIR_data: |
524 | case TOK_ASM_bss: |
579 | case TOK_ASMDIR_bss: |
525 | { |
580 | { |
526 | char sname[64]; |
581 | char sname[64]; |
527 | tok1 = tok; |
582 | tok1 = tok; |
528 | n = 0; |
583 | n = 0; |
529 | next(); |
584 | next(); |
530 | if (tok != ';' && tok != TOK_LINEFEED) { |
585 | if (tok != ';' && tok != TOK_LINEFEED) { |
531 | n = asm_int_expr(s1); |
586 | n = asm_int_expr(s1); |
532 | next(); |
587 | next(); |
533 | } |
588 | } |
- | 589 | if (n) |
|
534 | sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n); |
590 | sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n); |
- | 591 | else |
|
- | 592 | sprintf(sname, "%s", get_tok_str(tok1, NULL)); |
|
535 | use_section(s1, sname); |
593 | use_section(s1, sname); |
536 | } |
594 | } |
537 | break; |
595 | break; |
- | 596 | case TOK_ASMDIR_file: |
|
- | 597 | { |
|
- | 598 | char filename[512]; |
|
- | 599 | ||
- | 600 | filename[0] = '\0'; |
|
- | 601 | next(); |
|
- | 602 | ||
- | 603 | if (tok == TOK_STR) |
|
- | 604 | pstrcat(filename, sizeof(filename), tokc.str.data); |
|
- | 605 | else |
|
- | 606 | pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); |
|
- | 607 | ||
- | 608 | if (s1->warn_unsupported) |
|
- | 609 | tcc_warning("ignoring .file %s", filename); |
|
- | 610 | ||
- | 611 | next(); |
|
- | 612 | } |
|
- | 613 | break; |
|
- | 614 | case TOK_ASMDIR_ident: |
|
- | 615 | { |
|
- | 616 | char ident[256]; |
|
- | 617 | ||
- | 618 | ident[0] = '\0'; |
|
- | 619 | next(); |
|
- | 620 | ||
- | 621 | if (tok == TOK_STR) |
|
- | 622 | pstrcat(ident, sizeof(ident), tokc.str.data); |
|
- | 623 | else |
|
- | 624 | pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); |
|
- | 625 | ||
- | 626 | if (s1->warn_unsupported) |
|
- | 627 | tcc_warning("ignoring .ident %s", ident); |
|
- | 628 | ||
- | 629 | next(); |
|
- | 630 | } |
|
- | 631 | break; |
|
- | 632 | case TOK_ASMDIR_size: |
|
- | 633 | { |
|
- | 634 | Sym *sym; |
|
- | 635 | ||
- | 636 | next(); |
|
- | 637 | sym = label_find(tok); |
|
- | 638 | if (!sym) { |
|
- | 639 | tcc_error("label not found: %s", get_tok_str(tok, NULL)); |
|
- | 640 | } |
|
- | 641 | ||
- | 642 | /* XXX .size name,label2-label1 */ |
|
- | 643 | if (s1->warn_unsupported) |
|
- | 644 | tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); |
|
- | 645 | ||
- | 646 | next(); |
|
- | 647 | skip(','); |
|
- | 648 | while (tok != '\n' && tok != CH_EOF) { |
|
- | 649 | next(); |
|
- | 650 | } |
|
- | 651 | } |
|
- | 652 | break; |
|
538 | case TOK_SECTION1: |
653 | case TOK_ASMDIR_type: |
- | 654 | { |
|
- | 655 | Sym *sym; |
|
- | 656 | const char *newtype; |
|
- | 657 | ||
- | 658 | next(); |
|
- | 659 | sym = label_find(tok); |
|
- | 660 | if (!sym) { |
|
- | 661 | sym = label_push(&s1->asm_labels, tok, 0); |
|
- | 662 | sym->type.t = VT_VOID; |
|
- | 663 | } |
|
- | 664 | ||
- | 665 | next(); |
|
- | 666 | skip(','); |
|
- | 667 | if (tok == TOK_STR) { |
|
- | 668 | newtype = tokc.str.data; |
|
- | 669 | } else { |
|
- | 670 | if (tok == '@' || tok == '%') |
|
- | 671 | next(); |
|
- | 672 | newtype = get_tok_str(tok, NULL); |
|
- | 673 | } |
|
- | 674 | ||
- | 675 | if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { |
|
- | 676 | sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; |
|
- | 677 | } |
|
- | 678 | else if (s1->warn_unsupported) |
|
- | 679 | tcc_warning("change type of '%s' from 0x%x to '%s' ignored", |
|
- | 680 | get_tok_str(sym->v, NULL), sym->type.t, newtype); |
|
- | 681 | ||
- | 682 | next(); |
|
- | 683 | } |
|
- | 684 | break; |
|
- | 685 | case TOK_ASMDIR_section: |
|
539 | { |
686 | { |
540 | char sname[256]; |
687 | char sname[256]; |
Line 541... | Line 688... | ||
541 | 688 | ||
542 | /* XXX: support more options */ |
689 | /* XXX: support more options */ |
543 | next(); |
690 | next(); |
544 | sname[0] = '\0'; |
691 | sname[0] = '\0'; |
545 | while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { |
692 | while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { |
546 | if (tok == TOK_STR) |
693 | if (tok == TOK_STR) |
547 | pstrcat(sname, sizeof(sname), tokc.cstr->data); |
694 | pstrcat(sname, sizeof(sname), tokc.str.data); |
548 | else |
695 | else |
549 | pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); |
696 | pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); |
550 | next(); |
697 | next(); |
551 | } |
698 | } |
552 | if (tok == ',') { |
699 | if (tok == ',') { |
553 | /* skip section options */ |
700 | /* skip section options */ |
554 | next(); |
701 | next(); |
555 | if (tok != TOK_STR) |
702 | if (tok != TOK_STR) |
556 | expect("string constant"); |
703 | expect("string constant"); |
- | 704 | next(); |
|
- | 705 | if (tok == ',') { |
|
- | 706 | next(); |
|
- | 707 | if (tok == '@' || tok == '%') |
|
- | 708 | next(); |
|
- | 709 | next(); |
|
557 | next(); |
710 | } |
558 | } |
711 | } |
559 | last_text_section = cur_text_section; |
712 | last_text_section = cur_text_section; |
560 | use_section(s1, sname); |
713 | use_section(s1, sname); |
561 | } |
714 | } |
562 | break; |
715 | break; |
563 | case TOK_ASM_previous: |
716 | case TOK_ASMDIR_previous: |
564 | { |
717 | { |
565 | Section *sec; |
718 | Section *sec; |
566 | next(); |
719 | next(); |
567 | if (!last_text_section) |
720 | if (!last_text_section) |
568 | error("no previous section referenced"); |
721 | tcc_error("no previous section referenced"); |
569 | sec = cur_text_section; |
722 | sec = cur_text_section; |
570 | use_section1(s1, last_text_section); |
723 | use_section1(s1, last_text_section); |
571 | last_text_section = sec; |
724 | last_text_section = sec; |
572 | } |
725 | } |
- | 726 | break; |
|
- | 727 | #ifdef TCC_TARGET_I386 |
|
- | 728 | case TOK_ASMDIR_code16: |
|
- | 729 | { |
|
- | 730 | next(); |
|
- | 731 | s1->seg_size = 16; |
|
- | 732 | } |
|
- | 733 | break; |
|
- | 734 | case TOK_ASMDIR_code32: |
|
- | 735 | { |
|
- | 736 | next(); |
|
- | 737 | s1->seg_size = 32; |
|
- | 738 | } |
|
- | 739 | break; |
|
- | 740 | #endif |
|
- | 741 | #ifdef TCC_TARGET_X86_64 |
|
- | 742 | /* added for compatibility with GAS */ |
|
- | 743 | case TOK_ASMDIR_code64: |
|
- | 744 | next(); |
|
- | 745 | break; |
|
573 | break; |
746 | #endif |
574 | default: |
747 | default: |
575 | error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); |
748 | tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); |
576 | break; |
749 | break; |
577 | } |
750 | } |
Line 617... | Line 790... | ||
617 | 790 | ||
Line 618... | Line 791... | ||
618 | /* XXX: undefine C labels */ |
791 | /* XXX: undefine C labels */ |
619 | 792 | ||
620 | ch = file->buf_ptr[0]; |
793 | ch = file->buf_ptr[0]; |
621 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
794 | tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
622 | parse_flags = PARSE_FLAG_ASM_COMMENTS; |
795 | parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR; |
623 | if (do_preprocess) |
796 | if (do_preprocess) |
624 | parse_flags |= PARSE_FLAG_PREPROCESS; |
797 | parse_flags |= PARSE_FLAG_PREPROCESS; |
625 | next(); |
798 | next(); |
Line 630... | Line 803... | ||
630 | redo: |
803 | redo: |
631 | if (tok == '#') { |
804 | if (tok == '#') { |
632 | /* horrible gas comment */ |
805 | /* horrible gas comment */ |
633 | while (tok != TOK_LINEFEED) |
806 | while (tok != TOK_LINEFEED) |
634 | next(); |
807 | next(); |
635 | } else if (tok == '.') { |
808 | } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) { |
636 | asm_parse_directive(s1); |
809 | asm_parse_directive(s1); |
637 | } else if (tok == TOK_PPNUM) { |
810 | } else if (tok == TOK_PPNUM) { |
638 | const char *p; |
811 | const char *p; |
639 | int n; |
812 | int n; |
640 | p = tokc.cstr->data; |
813 | p = tokc.str.data; |
641 | n = strtoul(p, (char **)&p, 10); |
814 | n = strtoul(p, (char **)&p, 10); |
642 | if (*p != '\0') |
815 | if (*p != '\0') |
643 | expect("':'"); |
816 | expect("':'"); |
644 | /* new local label */ |
817 | /* new local label */ |
645 | asm_new_label(s1, asm_get_local_label_name(s1, n), 1); |
818 | asm_new_label(s1, asm_get_local_label_name(s1, n), 1); |
Line 677... | Line 850... | ||
677 | 850 | ||
678 | return 0; |
851 | return 0; |
Line 679... | Line 852... | ||
679 | } |
852 | } |
680 | 853 | ||
681 | /* Assemble the current file */ |
854 | /* Assemble the current file */ |
682 | static int tcc_assemble(TCCState *s1, int do_preprocess) |
855 | ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) |
683 | { |
856 | { |
Line 684... | Line 857... | ||
684 | Sym *define_start; |
857 | Sym *define_start; |
Line 690... | Line 863... | ||
690 | cur_text_section = text_section; |
863 | cur_text_section = text_section; |
691 | ind = cur_text_section->data_offset; |
864 | ind = cur_text_section->data_offset; |
Line 692... | Line 865... | ||
692 | 865 | ||
Line -... | Line 866... | ||
- | 866 | define_start = define_stack; |
|
- | 867 | ||
- | 868 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
|
- | 869 | symbols can be safely used */ |
|
- | 870 | put_elf_sym(symtab_section, 0, 0, |
|
- | 871 | ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, |
|
693 | define_start = define_stack; |
872 | SHN_ABS, file->filename); |
Line 694... | Line 873... | ||
694 | 873 | ||
Line 695... | Line 874... | ||
695 | ret = tcc_assemble_internal(s1, do_preprocess); |
874 | ret = tcc_assemble_internal(s1, do_preprocess); |
Line 707... | Line 886... | ||
707 | /* assemble the string 'str' in the current C compilation unit without |
886 | /* assemble the string 'str' in the current C compilation unit without |
708 | C preprocessing. NOTE: str is modified by modifying the '\0' at the |
887 | C preprocessing. NOTE: str is modified by modifying the '\0' at the |
709 | end */ |
888 | end */ |
710 | static void tcc_assemble_inline(TCCState *s1, char *str, int len) |
889 | static void tcc_assemble_inline(TCCState *s1, char *str, int len) |
711 | { |
890 | { |
712 | BufferedFile *bf, *saved_file; |
891 | int saved_parse_flags; |
713 | int saved_parse_flags, *saved_macro_ptr; |
892 | const int *saved_macro_ptr; |
Line 714... | Line -... | ||
714 | - | ||
715 | bf = tcc_malloc(sizeof(BufferedFile)); |
- | |
716 | memset(bf, 0, sizeof(BufferedFile)); |
- | |
717 | bf->fd = -1; |
- | |
718 | bf->buf_ptr = str; |
- | |
719 | bf->buf_end = str + len; |
- | |
720 | str[len] = CH_EOB; |
- | |
721 | /* same name as current file so that errors are correctly |
- | |
722 | reported */ |
- | |
723 | pstrcpy(bf->filename, sizeof(bf->filename), file->filename); |
- | |
724 | bf->line_num = file->line_num; |
- | |
725 | saved_file = file; |
- | |
726 | file = bf; |
893 | |
727 | saved_parse_flags = parse_flags; |
894 | saved_parse_flags = parse_flags; |
728 | saved_macro_ptr = macro_ptr; |
- | |
Line -... | Line 895... | ||
- | 895 | saved_macro_ptr = macro_ptr; |
|
- | 896 | ||
- | 897 | tcc_open_bf(s1, ":asm:", len); |
|
- | 898 | memcpy(file->buffer, str, len); |
|
729 | macro_ptr = NULL; |
899 | |
- | 900 | macro_ptr = NULL; |
|
Line 730... | Line 901... | ||
730 | 901 | tcc_assemble_internal(s1, 0); |
|
731 | tcc_assemble_internal(s1, 0); |
902 | tcc_close(); |
732 | - | ||
733 | parse_flags = saved_parse_flags; |
- | |
734 | macro_ptr = saved_macro_ptr; |
903 | |
Line 735... | Line 904... | ||
735 | file = saved_file; |
904 | parse_flags = saved_parse_flags; |
736 | tcc_free(bf); |
905 | macro_ptr = saved_macro_ptr; |
737 | } |
906 | } |
738 | 907 | ||
739 | /* find a constraint by its number or id (gcc 3 extended |
908 | /* find a constraint by its number or id (gcc 3 extended |
740 | syntax). return -1 if not found. Return in *pp in char after the |
909 | syntax). return -1 if not found. Return in *pp in char after the |
741 | constraint */ |
910 | constraint */ |
742 | static int find_constraint(ASMOperand *operands, int nb_operands, |
911 | ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, |
743 | const char *name, const char **pp) |
912 | const char *name, const char **pp) |
Line 799... | Line 968... | ||
799 | if (*str == 'c' || *str == 'n' || |
968 | if (*str == 'c' || *str == 'n' || |
800 | *str == 'b' || *str == 'w' || *str == 'h') |
969 | *str == 'b' || *str == 'w' || *str == 'h') |
801 | modifier = *str++; |
970 | modifier = *str++; |
802 | index = find_constraint(operands, nb_operands, str, &str); |
971 | index = find_constraint(operands, nb_operands, str, &str); |
803 | if (index < 0) |
972 | if (index < 0) |
804 | error("invalid operand reference after %%"); |
973 | tcc_error("invalid operand reference after %%"); |
805 | op = &operands[index]; |
974 | op = &operands[index]; |
806 | sv = *op->vt; |
975 | sv = *op->vt; |
807 | if (op->reg >= 0) { |
976 | if (op->reg >= 0) { |
808 | sv.r = op->reg; |
977 | sv.r = op->reg; |
809 | if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) |
978 | if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) |
810 | sv.r |= VT_LVAL; |
979 | sv.r |= VT_LVAL; |
811 | } |
980 | } |
812 | subst_asm_operand(out_str, &sv, modifier); |
981 | subst_asm_operand(out_str, &sv, modifier); |
813 | } else { |
982 | } else { |
814 | add_char: |
983 | add_char: |
Line 828... | Line 997... | ||
828 | 997 | ||
829 | if (tok != ':') { |
998 | if (tok != ':') { |
830 | nb_operands = *nb_operands_ptr; |
999 | nb_operands = *nb_operands_ptr; |
831 | for(;;) { |
1000 | for(;;) { |
832 | if (nb_operands >= MAX_ASM_OPERANDS) |
1001 | if (nb_operands >= MAX_ASM_OPERANDS) |
833 | error("too many asm operands"); |
1002 | tcc_error("too many asm operands"); |
834 | op = &operands[nb_operands++]; |
1003 | op = &operands[nb_operands++]; |
835 | op->id = 0; |
1004 | op->id = 0; |
836 | if (tok == '[') { |
1005 | if (tok == '[') { |
837 | next(); |
1006 | next(); |
Line 841... | Line 1010... | ||
841 | next(); |
1010 | next(); |
842 | skip(']'); |
1011 | skip(']'); |
843 | } |
1012 | } |
844 | if (tok != TOK_STR) |
1013 | if (tok != TOK_STR) |
845 | expect("string constant"); |
1014 | expect("string constant"); |
846 | op->constraint = tcc_malloc(tokc.cstr->size); |
1015 | op->constraint = tcc_malloc(tokc.str.size); |
847 | strcpy(op->constraint, tokc.cstr->data); |
1016 | strcpy(op->constraint, tokc.str.data); |
848 | next(); |
1017 | next(); |
849 | skip('('); |
1018 | skip('('); |
850 | gexpr(); |
1019 | gexpr(); |
851 | if (is_output) { |
1020 | if (is_output) { |
852 | test_lvalue(); |
1021 | test_lvalue(); |
Line 872... | Line 1041... | ||
872 | } |
1041 | } |
873 | *nb_operands_ptr = nb_operands; |
1042 | *nb_operands_ptr = nb_operands; |
874 | } |
1043 | } |
875 | } |
1044 | } |
Line 876... | Line -... | ||
876 | - | ||
877 | static void parse_asm_str(CString *astr) |
- | |
878 | { |
- | |
879 | skip('('); |
- | |
880 | /* read the string */ |
- | |
881 | if (tok != TOK_STR) |
- | |
882 | expect("string constant"); |
- | |
883 | cstr_new(astr); |
- | |
884 | while (tok == TOK_STR) { |
- | |
885 | /* XXX: add \0 handling too ? */ |
- | |
886 | cstr_cat(astr, tokc.cstr->data); |
- | |
887 | next(); |
- | |
888 | } |
- | |
889 | cstr_ccat(astr, '\0'); |
- | |
890 | } |
- | |
891 | 1045 | ||
892 | /* parse the GCC asm() instruction */ |
1046 | /* parse the GCC asm() instruction */ |
893 | static void asm_instr(void) |
1047 | ST_FUNC void asm_instr(void) |
894 | { |
1048 | { |
895 | CString astr, astr1; |
1049 | CString astr, astr1; |
896 | ASMOperand operands[MAX_ASM_OPERANDS]; |
1050 | ASMOperand operands[MAX_ASM_OPERANDS]; |
897 | int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg; |
1051 | int nb_outputs, nb_operands, i, must_subst, out_reg; |
Line 898... | Line 1052... | ||
898 | uint8_t clobber_regs[NB_ASM_REGS]; |
1052 | uint8_t clobber_regs[NB_ASM_REGS]; |
899 | 1053 | ||
900 | next(); |
1054 | next(); |
Line 914... | Line 1068... | ||
914 | /* output args */ |
1068 | /* output args */ |
915 | parse_asm_operands(operands, &nb_operands, 1); |
1069 | parse_asm_operands(operands, &nb_operands, 1); |
916 | nb_outputs = nb_operands; |
1070 | nb_outputs = nb_operands; |
917 | if (tok == ':') { |
1071 | if (tok == ':') { |
918 | next(); |
1072 | next(); |
- | 1073 | if (tok != ')') { |
|
919 | /* input args */ |
1074 | /* input args */ |
920 | parse_asm_operands(operands, &nb_operands, 0); |
1075 | parse_asm_operands(operands, &nb_operands, 0); |
921 | if (tok == ':') { |
1076 | if (tok == ':') { |
922 | /* clobber list */ |
1077 | /* clobber list */ |
923 | /* XXX: handle registers */ |
1078 | /* XXX: handle registers */ |
924 | next(); |
1079 | next(); |
925 | for(;;) { |
1080 | for(;;) { |
926 | if (tok != TOK_STR) |
1081 | if (tok != TOK_STR) |
927 | expect("string constant"); |
1082 | expect("string constant"); |
928 | asm_clobber(clobber_regs, tokc.cstr->data); |
1083 | asm_clobber(clobber_regs, tokc.str.data); |
929 | next(); |
1084 | next(); |
930 | if (tok == ',') { |
1085 | if (tok == ',') { |
931 | next(); |
1086 | next(); |
932 | } else { |
1087 | } else { |
933 | break; |
1088 | break; |
934 | } |
1089 | } |
935 | } |
1090 | } |
936 | } |
1091 | } |
937 | } |
1092 | } |
938 | } |
1093 | } |
- | 1094 | } |
|
939 | skip(')'); |
1095 | skip(')'); |
940 | /* NOTE: we do not eat the ';' so that we can restore the current |
1096 | /* NOTE: we do not eat the ';' so that we can restore the current |
941 | token after the assembler parsing */ |
1097 | token after the assembler parsing */ |
942 | if (tok != ';') |
1098 | if (tok != ';') |
943 | expect("';'"); |
1099 | expect("';'"); |
944 | nb_inputs = nb_operands - nb_outputs; |
- | |
Line 945... | Line 1100... | ||
945 | 1100 | ||
946 | /* save all values in the memory */ |
1101 | /* save all values in the memory */ |
Line 947... | Line 1102... | ||
947 | save_regs(0); |
1102 | save_regs(0); |
Line 987... | Line 1142... | ||
987 | vpop(); |
1142 | vpop(); |
988 | } |
1143 | } |
989 | cstr_free(&astr1); |
1144 | cstr_free(&astr1); |
990 | } |
1145 | } |
Line 991... | Line 1146... | ||
991 | 1146 | ||
992 | static void asm_global_instr(void) |
1147 | ST_FUNC void asm_global_instr(void) |
993 | { |
1148 | { |
Line 994... | Line 1149... | ||
994 | CString astr; |
1149 | CString astr; |
995 | 1150 | ||
Line 1015... | Line 1170... | ||
1015 | /* restore the current C token */ |
1170 | /* restore the current C token */ |
1016 | next(); |
1171 | next(); |
Line 1017... | Line 1172... | ||
1017 | 1172 | ||
1018 | cstr_free(&astr); |
1173 | cstr_free(&astr); |
- | 1174 | } |