Added missing file.
[tinycc/k1w1.git] / tccasm.c
blobcb47f3ea0f485b036be7ef458dc93e540ec91cce
1 /*
2 * GAS like assembler for TCC
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "tcc.h"
22 #ifdef TCC_TARGET_I386
23 #include "i386-asm-config.h"
24 #endif
26 #ifdef TCC_TARGET_X86_64
27 #include "x86_64-asm-config.h"
28 #endif
30 static int asm_get_local_label_name(TCCState *s1, unsigned int n)
32 char buf[64];
33 TokenSym *ts;
35 snprintf(buf, sizeof(buf), "L..%u", n);
36 ts = tok_alloc(buf, strlen(buf));
37 return ts->tok;
40 /* We do not use the C expression parser to handle symbols. Maybe the
41 C expression parser could be tweaked to do so. */
43 static void asm_expr_unary(TCCState *s1, ExprValue *pe)
45 Sym *sym;
46 int op, n, label;
47 const char *p;
49 switch(tok) {
50 case TOK_PPNUM:
51 p = tokc.cstr->data;
52 n = strtoul(p, (char **)&p, 0);
53 if (*p == 'b' || *p == 'f') {
54 /* backward or forward label */
55 label = asm_get_local_label_name(s1, n);
56 sym = label_find(label);
57 if (*p == 'b') {
58 /* backward : find the last corresponding defined label */
59 if (sym && sym->r == 0)
60 sym = sym->prev_tok;
61 if (!sym)
62 error("local label '%d' not found backward", n);
63 } else {
64 /* forward */
65 if (!sym || sym->r) {
66 /* if the last label is defined, then define a new one */
67 sym = label_push(&s1->asm_labels, label, 0);
68 sym->type.t = VT_STATIC | VT_VOID;
71 pe->v = 0;
72 pe->sym = sym;
73 } else if (*p == '\0') {
74 pe->v = n;
75 pe->sym = NULL;
76 } else {
77 error("invalid number syntax");
79 next();
80 break;
81 case '+':
82 next();
83 asm_expr_unary(s1, pe);
84 break;
85 case '-':
86 case '~':
87 op = tok;
88 next();
89 asm_expr_unary(s1, pe);
90 if (pe->sym)
91 error("invalid operation with label");
92 if (op == '-')
93 pe->v = -pe->v;
94 else
95 pe->v = ~pe->v;
96 break;
97 case TOK_CCHAR:
98 case TOK_LCHAR:
99 pe->v = tokc.i;
100 pe->sym = NULL;
101 next();
102 break;
103 case '(':
104 next();
105 asm_expr(s1, pe);
106 skip(')');
107 break;
108 default:
109 if (tok >= TOK_IDENT) {
110 /* label case : if the label was not found, add one */
111 sym = label_find(tok);
112 if (!sym) {
113 sym = label_push(&s1->asm_labels, tok, 0);
114 /* NOTE: by default, the symbol is global */
115 sym->type.t = VT_VOID;
117 if (sym->r == SHN_ABS) {
118 /* if absolute symbol, no need to put a symbol value */
119 pe->v = sym->jnext;
120 pe->sym = NULL;
121 } else {
122 pe->v = 0;
123 pe->sym = sym;
125 next();
126 } else {
127 error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
129 break;
133 static void asm_expr_prod(TCCState *s1, ExprValue *pe)
135 int op;
136 ExprValue e2;
138 asm_expr_unary(s1, pe);
139 for(;;) {
140 op = tok;
141 if (op != '*' && op != '/' && op != '%' &&
142 op != TOK_SHL && op != TOK_SAR)
143 break;
144 next();
145 asm_expr_unary(s1, &e2);
146 if (pe->sym || e2.sym)
147 error("invalid operation with label");
148 switch(op) {
149 case '*':
150 pe->v *= e2.v;
151 break;
152 case '/':
153 if (e2.v == 0) {
154 div_error:
155 error("division by zero");
157 pe->v /= e2.v;
158 break;
159 case '%':
160 if (e2.v == 0)
161 goto div_error;
162 pe->v %= e2.v;
163 break;
164 case TOK_SHL:
165 pe->v <<= e2.v;
166 break;
167 default:
168 case TOK_SAR:
169 pe->v >>= e2.v;
170 break;
175 static void asm_expr_logic(TCCState *s1, ExprValue *pe)
177 int op;
178 ExprValue e2;
180 asm_expr_prod(s1, pe);
181 for(;;) {
182 op = tok;
183 if (op != '&' && op != '|' && op != '^')
184 break;
185 next();
186 asm_expr_prod(s1, &e2);
187 if (pe->sym || e2.sym)
188 error("invalid operation with label");
189 switch(op) {
190 case '&':
191 pe->v &= e2.v;
192 break;
193 case '|':
194 pe->v |= e2.v;
195 break;
196 default:
197 case '^':
198 pe->v ^= e2.v;
199 break;
204 static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
206 int op;
207 ExprValue e2;
209 asm_expr_logic(s1, pe);
210 for(;;) {
211 op = tok;
212 if (op != '+' && op != '-')
213 break;
214 next();
215 asm_expr_logic(s1, &e2);
216 if (op == '+') {
217 if (pe->sym != NULL && e2.sym != NULL)
218 goto cannot_relocate;
219 pe->v += e2.v;
220 if (pe->sym == NULL && e2.sym != NULL)
221 pe->sym = e2.sym;
222 } else {
223 pe->v -= e2.v;
224 /* NOTE: we are less powerful than gas in that case
225 because we store only one symbol in the expression */
226 if (!pe->sym && !e2.sym) {
227 /* OK */
228 } else if (pe->sym && !e2.sym) {
229 /* OK */
230 } else if (pe->sym && e2.sym) {
231 if (pe->sym == e2.sym) {
232 /* OK */
233 } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
234 /* we also accept defined symbols in the same section */
235 pe->v += pe->sym->jnext - e2.sym->jnext;
236 } else {
237 goto cannot_relocate;
239 pe->sym = NULL; /* same symbols can be substracted to NULL */
240 } else {
241 cannot_relocate:
242 error("invalid operation with label");
248 void asm_expr(TCCState *s1, ExprValue *pe)
250 asm_expr_sum(s1, pe);
253 int asm_int_expr(TCCState *s1)
255 ExprValue e;
256 asm_expr(s1, &e);
257 if (e.sym)
258 expect("constant");
259 return e.v;
262 /* NOTE: the same name space as C labels is used to avoid using too
263 much memory when storing labels in TokenStrings */
264 static void asm_new_label1(TCCState *s1, int label, int is_local,
265 int sh_num, int value)
267 Sym *sym;
269 sym = label_find(label);
270 if (sym) {
271 if (sym->r) {
272 /* the label is already defined */
273 if (!is_local) {
274 error("assembler label '%s' already defined",
275 get_tok_str(label, NULL));
276 } else {
277 /* redefinition of local labels is possible */
278 goto new_label;
281 } else {
282 new_label:
283 sym = label_push(&s1->asm_labels, label, 0);
284 sym->type.t = VT_STATIC | VT_VOID;
286 sym->r = sh_num;
287 sym->jnext = value;
290 static void asm_new_label(TCCState *s1, int label, int is_local)
292 asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
295 static void asm_free_labels(TCCState *st)
297 Sym *s, *s1;
298 Section *sec;
300 for(s = st->asm_labels; s != NULL; s = s1) {
301 s1 = s->prev;
302 /* define symbol value in object file */
303 if (s->r) {
304 if (s->r == SHN_ABS)
305 sec = SECTION_ABS;
306 else
307 sec = st->sections[s->r];
308 put_extern_sym2(s, sec, s->jnext, 0, 0);
310 /* remove label */
311 table_ident[s->v - TOK_IDENT]->sym_label = NULL;
312 sym_free(s);
314 st->asm_labels = NULL;
317 static void use_section1(TCCState *s1, Section *sec)
319 cur_text_section->data_offset = ind;
320 cur_text_section = sec;
321 ind = cur_text_section->data_offset;
324 static void use_section(TCCState *s1, const char *name)
326 Section *sec;
327 sec = find_section(s1, name);
328 use_section1(s1, sec);
331 static void asm_parse_directive(TCCState *s1)
333 int n, offset, v, size, tok1;
334 Section *sec;
335 uint8_t *ptr;
337 /* assembler directive */
338 next();
339 sec = cur_text_section;
340 switch(tok) {
341 case TOK_ASM_align:
342 case TOK_ASM_skip:
343 case TOK_ASM_space:
344 tok1 = tok;
345 next();
346 n = asm_int_expr(s1);
347 if (tok1 == TOK_ASM_align) {
348 if (n < 0 || (n & (n-1)) != 0)
349 error("alignment must be a positive power of two");
350 offset = (ind + n - 1) & -n;
351 size = offset - ind;
352 /* the section must have a compatible alignment */
353 if (sec->sh_addralign < n)
354 sec->sh_addralign = n;
355 } else {
356 size = n;
358 v = 0;
359 if (tok == ',') {
360 next();
361 v = asm_int_expr(s1);
363 zero_pad:
364 if (sec->sh_type != SHT_NOBITS) {
365 sec->data_offset = ind;
366 ptr = section_ptr_add(sec, size);
367 memset(ptr, v, size);
369 ind += size;
370 break;
371 case TOK_ASM_quad:
372 next();
373 for(;;) {
374 uint64_t vl;
375 const char *p;
377 p = tokc.cstr->data;
378 if (tok != TOK_PPNUM) {
379 error_constant:
380 error("64 bit constant");
382 vl = strtoll(p, (char **)&p, 0);
383 if (*p != '\0')
384 goto error_constant;
385 next();
386 if (sec->sh_type != SHT_NOBITS) {
387 /* XXX: endianness */
388 gen_le32(vl);
389 gen_le32(vl >> 32);
390 } else {
391 ind += 8;
393 if (tok != ',')
394 break;
395 next();
397 break;
398 case TOK_ASM_byte:
399 size = 1;
400 goto asm_data;
401 case TOK_ASM_word:
402 case TOK_SHORT:
403 size = 2;
404 goto asm_data;
405 case TOK_LONG:
406 case TOK_INT:
407 size = 4;
408 asm_data:
409 next();
410 for(;;) {
411 ExprValue e;
412 asm_expr(s1, &e);
413 if (sec->sh_type != SHT_NOBITS) {
414 if (size == 4) {
415 gen_expr32(&e);
416 } else {
417 if (e.sym)
418 expect("constant");
419 if (size == 1)
420 g(e.v);
421 else
422 gen_le16(e.v);
424 } else {
425 ind += size;
427 if (tok != ',')
428 break;
429 next();
431 break;
432 case TOK_ASM_fill:
434 int repeat, size, val, i, j;
435 uint8_t repeat_buf[8];
436 next();
437 repeat = asm_int_expr(s1);
438 if (repeat < 0) {
439 error("repeat < 0; .fill ignored");
440 break;
442 size = 1;
443 val = 0;
444 if (tok == ',') {
445 next();
446 size = asm_int_expr(s1);
447 if (size < 0) {
448 error("size < 0; .fill ignored");
449 break;
451 if (size > 8)
452 size = 8;
453 if (tok == ',') {
454 next();
455 val = asm_int_expr(s1);
458 /* XXX: endianness */
459 repeat_buf[0] = val;
460 repeat_buf[1] = val >> 8;
461 repeat_buf[2] = val >> 16;
462 repeat_buf[3] = val >> 24;
463 repeat_buf[4] = 0;
464 repeat_buf[5] = 0;
465 repeat_buf[6] = 0;
466 repeat_buf[7] = 0;
467 for(i = 0; i < repeat; i++) {
468 for(j = 0; j < size; j++) {
469 g(repeat_buf[j]);
473 break;
474 case TOK_ASM_org:
476 unsigned long n;
477 next();
478 /* XXX: handle section symbols too */
479 n = asm_int_expr(s1);
480 if (n < ind)
481 error("attempt to .org backwards");
482 v = 0;
483 size = n - ind;
484 goto zero_pad;
486 break;
487 case TOK_ASM_globl:
488 case TOK_ASM_global:
490 Sym *sym;
492 next();
493 sym = label_find(tok);
494 if (!sym) {
495 sym = label_push(&s1->asm_labels, tok, 0);
496 sym->type.t = VT_VOID;
498 sym->type.t &= ~VT_STATIC;
499 next();
501 break;
502 case TOK_ASM_string:
503 case TOK_ASM_ascii:
504 case TOK_ASM_asciz:
506 const uint8_t *p;
507 int i, size, t;
509 t = tok;
510 next();
511 for(;;) {
512 if (tok != TOK_STR)
513 expect("string constant");
514 p = tokc.cstr->data;
515 size = tokc.cstr->size;
516 if (t == TOK_ASM_ascii && size > 0)
517 size--;
518 for(i = 0; i < size; i++)
519 g(p[i]);
520 next();
521 if (tok == ',') {
522 next();
523 } else if (tok != TOK_STR) {
524 break;
528 break;
529 case TOK_ASM_text:
530 case TOK_ASM_data:
531 case TOK_ASM_bss:
533 char sname[64];
534 tok1 = tok;
535 n = 0;
536 next();
537 if (tok != ';' && tok != TOK_LINEFEED) {
538 n = asm_int_expr(s1);
539 next();
541 sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
542 use_section(s1, sname);
544 break;
545 case TOK_SECTION1:
547 char sname[256];
549 /* XXX: support more options */
550 next();
551 sname[0] = '\0';
552 while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
553 if (tok == TOK_STR)
554 pstrcat(sname, sizeof(sname), tokc.cstr->data);
555 else
556 pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
557 next();
559 if (tok == ',') {
560 /* skip section options */
561 next();
562 if (tok != TOK_STR)
563 expect("string constant");
564 next();
566 last_text_section = cur_text_section;
567 use_section(s1, sname);
569 break;
570 case TOK_ASM_previous:
572 Section *sec;
573 next();
574 if (!last_text_section)
575 error("no previous section referenced");
576 sec = cur_text_section;
577 use_section1(s1, last_text_section);
578 last_text_section = sec;
580 break;
581 #ifdef TCC_TARGET_I386
582 case TOK_ASM_code16:
584 next();
585 s1->seg_size = 16;
587 break;
588 case TOK_ASM_code32:
590 next();
591 s1->seg_size = 32;
593 break;
594 #endif
595 #ifdef TCC_TARGET_X86_64
596 /* added for compatibility with GAS */
597 case TOK_ASM_code64:
598 next();
599 break;
600 #endif
601 default:
602 error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
603 break;
608 /* assemble a file */
609 static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
611 int opcode;
613 #if 0
614 /* print stats about opcodes */
616 const ASMInstr *pa;
617 int freq[4];
618 int op_vals[500];
619 int nb_op_vals, i, j;
621 nb_op_vals = 0;
622 memset(freq, 0, sizeof(freq));
623 for(pa = asm_instrs; pa->sym != 0; pa++) {
624 freq[pa->nb_ops]++;
625 for(i=0;i<pa->nb_ops;i++) {
626 for(j=0;j<nb_op_vals;j++) {
627 if (pa->op_type[i] == op_vals[j])
628 goto found;
630 op_vals[nb_op_vals++] = pa->op_type[i];
631 found: ;
634 for(i=0;i<nb_op_vals;i++) {
635 int v = op_vals[i];
636 if ((v & (v - 1)) != 0)
637 printf("%3d: %08x\n", i, v);
639 printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
640 sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr),
641 freq[0], freq[1], freq[2], freq[3]);
643 #endif
645 /* XXX: undefine C labels */
647 ch = file->buf_ptr[0];
648 tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
649 parse_flags = PARSE_FLAG_ASM_COMMENTS;
650 if (do_preprocess)
651 parse_flags |= PARSE_FLAG_PREPROCESS;
652 next();
653 for(;;) {
654 if (tok == TOK_EOF)
655 break;
656 parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
657 redo:
658 if (tok == '#') {
659 /* horrible gas comment */
660 while (tok != TOK_LINEFEED)
661 next();
662 } else if (tok == '.') {
663 asm_parse_directive(s1);
664 } else if (tok == TOK_PPNUM) {
665 const char *p;
666 int n;
667 p = tokc.cstr->data;
668 n = strtoul(p, (char **)&p, 10);
669 if (*p != '\0')
670 expect("':'");
671 /* new local label */
672 asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
673 next();
674 skip(':');
675 goto redo;
676 } else if (tok >= TOK_IDENT) {
677 /* instruction or label */
678 opcode = tok;
679 next();
680 if (tok == ':') {
681 /* new label */
682 asm_new_label(s1, opcode, 0);
683 next();
684 goto redo;
685 } else if (tok == '=') {
686 int n;
687 next();
688 n = asm_int_expr(s1);
689 asm_new_label1(s1, opcode, 0, SHN_ABS, n);
690 goto redo;
691 } else {
692 asm_opcode(s1, opcode);
695 /* end of line */
696 if (tok != ';' && tok != TOK_LINEFEED){
697 expect("end of line");
699 parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
700 next();
703 asm_free_labels(s1);
705 return 0;
708 /* Assemble the current file */
709 int tcc_assemble(TCCState *s1, int do_preprocess)
711 Sym *define_start;
712 int ret;
714 preprocess_init(s1);
716 /* default section is text */
717 cur_text_section = text_section;
718 ind = cur_text_section->data_offset;
720 define_start = define_stack;
722 ret = tcc_assemble_internal(s1, do_preprocess);
724 cur_text_section->data_offset = ind;
726 free_defines(define_start);
728 return ret;
731 /********************************************************************/
732 /* GCC inline asm support */
734 /* assemble the string 'str' in the current C compilation unit without
735 C preprocessing. NOTE: str is modified by modifying the '\0' at the
736 end */
737 static void tcc_assemble_inline(TCCState *s1, char *str, int len)
739 BufferedFile *bf, *saved_file;
740 int saved_parse_flags, *saved_macro_ptr;
742 bf = tcc_malloc(sizeof(BufferedFile));
743 memset(bf, 0, sizeof(BufferedFile));
744 bf->fd = -1;
745 bf->buf_ptr = str;
746 bf->buf_end = str + len;
747 str[len] = CH_EOB;
748 /* same name as current file so that errors are correctly
749 reported */
750 pstrcpy(bf->filename, sizeof(bf->filename), file->filename);
751 bf->line_num = file->line_num;
752 saved_file = file;
753 file = bf;
754 saved_parse_flags = parse_flags;
755 saved_macro_ptr = macro_ptr;
756 macro_ptr = NULL;
758 tcc_assemble_internal(s1, 0);
760 parse_flags = saved_parse_flags;
761 macro_ptr = saved_macro_ptr;
762 file = saved_file;
763 tcc_free(bf);
766 /* find a constraint by its number or id (gcc 3 extended
767 syntax). return -1 if not found. Return in *pp in char after the
768 constraint */
769 int find_constraint(ASMOperand *operands, int nb_operands,
770 const char *name, const char **pp)
772 int index;
773 TokenSym *ts;
774 const char *p;
776 if (isnum(*name)) {
777 index = 0;
778 while (isnum(*name)) {
779 index = (index * 10) + (*name) - '0';
780 name++;
782 if ((unsigned)index >= nb_operands)
783 index = -1;
784 } else if (*name == '[') {
785 name++;
786 p = strchr(name, ']');
787 if (p) {
788 ts = tok_alloc(name, p - name);
789 for(index = 0; index < nb_operands; index++) {
790 if (operands[index].id == ts->tok)
791 goto found;
793 index = -1;
794 found:
795 name = p + 1;
796 } else {
797 index = -1;
799 } else {
800 index = -1;
802 if (pp)
803 *pp = name;
804 return index;
807 static void subst_asm_operands(ASMOperand *operands, int nb_operands,
808 int nb_outputs,
809 CString *out_str, CString *in_str)
811 int c, index, modifier;
812 const char *str;
813 ASMOperand *op;
814 SValue sv;
816 cstr_new(out_str);
817 str = in_str->data;
818 for(;;) {
819 c = *str++;
820 if (c == '%') {
821 if (*str == '%') {
822 str++;
823 goto add_char;
825 modifier = 0;
826 if (*str == 'c' || *str == 'n' ||
827 *str == 'b' || *str == 'w' || *str == 'h')
828 modifier = *str++;
829 index = find_constraint(operands, nb_operands, str, &str);
830 if (index < 0)
831 error("invalid operand reference after %%");
832 op = &operands[index];
833 sv = *op->vt;
834 if (op->reg >= 0) {
835 sv.r = op->reg;
836 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
837 sv.r |= VT_LVAL;
839 subst_asm_operand(out_str, &sv, modifier);
840 } else {
841 add_char:
842 cstr_ccat(out_str, c);
843 if (c == '\0')
844 break;
850 static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
851 int is_output)
853 ASMOperand *op;
854 int nb_operands;
856 if (tok != ':') {
857 nb_operands = *nb_operands_ptr;
858 for(;;) {
859 if (nb_operands >= MAX_ASM_OPERANDS)
860 error("too many asm operands");
861 op = &operands[nb_operands++];
862 op->id = 0;
863 if (tok == '[') {
864 next();
865 if (tok < TOK_IDENT)
866 expect("identifier");
867 op->id = tok;
868 next();
869 skip(']');
871 if (tok != TOK_STR)
872 expect("string constant");
873 op->constraint = tcc_malloc(tokc.cstr->size);
874 strcpy(op->constraint, tokc.cstr->data);
875 next();
876 skip('(');
877 gexpr();
878 if (is_output) {
879 test_lvalue();
880 } else {
881 /* we want to avoid LLOCAL case, except when the 'm'
882 constraint is used. Note that it may come from
883 register storage, so we need to convert (reg)
884 case */
885 if ((vtop->r & VT_LVAL) &&
886 ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
887 (vtop->r & VT_VALMASK) < VT_CONST) &&
888 !strchr(op->constraint, 'm')) {
889 gv(RC_INT);
892 op->vt = vtop;
893 skip(')');
894 if (tok == ',') {
895 next();
896 } else {
897 break;
900 *nb_operands_ptr = nb_operands;
904 void parse_asm_str(CString *astr)
906 skip('(');
907 /* read the string */
908 if (tok != TOK_STR)
909 expect("string constant");
910 cstr_new(astr);
911 while (tok == TOK_STR) {
912 /* XXX: add \0 handling too ? */
913 cstr_cat(astr, tokc.cstr->data);
914 next();
916 cstr_ccat(astr, '\0');
919 /* parse the GCC asm() instruction */
920 void asm_instr(void)
922 CString astr, astr1;
923 ASMOperand operands[MAX_ASM_OPERANDS];
924 int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
925 uint8_t clobber_regs[NB_ASM_REGS];
927 next();
928 /* since we always generate the asm() instruction, we can ignore
929 volatile */
930 if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
931 next();
933 parse_asm_str(&astr);
934 nb_operands = 0;
935 nb_outputs = 0;
936 must_subst = 0;
937 memset(clobber_regs, 0, sizeof(clobber_regs));
938 if (tok == ':') {
939 next();
940 must_subst = 1;
941 /* output args */
942 parse_asm_operands(operands, &nb_operands, 1);
943 nb_outputs = nb_operands;
944 if (tok == ':') {
945 next();
946 if (tok != ')') {
947 /* input args */
948 parse_asm_operands(operands, &nb_operands, 0);
949 if (tok == ':') {
950 /* clobber list */
951 /* XXX: handle registers */
952 next();
953 for(;;) {
954 if (tok != TOK_STR)
955 expect("string constant");
956 asm_clobber(clobber_regs, tokc.cstr->data);
957 next();
958 if (tok == ',') {
959 next();
960 } else {
961 break;
968 skip(')');
969 /* NOTE: we do not eat the ';' so that we can restore the current
970 token after the assembler parsing */
971 if (tok != ';')
972 expect("';'");
973 nb_inputs = nb_operands - nb_outputs;
975 /* save all values in the memory */
976 save_regs(0);
978 /* compute constraints */
979 asm_compute_constraints(operands, nb_operands, nb_outputs,
980 clobber_regs, &out_reg);
982 /* substitute the operands in the asm string. No substitution is
983 done if no operands (GCC behaviour) */
984 #ifdef ASM_DEBUG
985 printf("asm: \"%s\"\n", (char *)astr.data);
986 #endif
987 if (must_subst) {
988 subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
989 cstr_free(&astr);
990 } else {
991 astr1 = astr;
993 #ifdef ASM_DEBUG
994 printf("subst_asm: \"%s\"\n", (char *)astr1.data);
995 #endif
997 /* generate loads */
998 asm_gen_code(operands, nb_operands, nb_outputs, 0,
999 clobber_regs, out_reg);
1001 /* assemble the string with tcc internal assembler */
1002 tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
1004 /* restore the current C token */
1005 next();
1007 /* store the output values if needed */
1008 asm_gen_code(operands, nb_operands, nb_outputs, 1,
1009 clobber_regs, out_reg);
1011 /* free everything */
1012 for(i=0;i<nb_operands;i++) {
1013 ASMOperand *op;
1014 op = &operands[i];
1015 tcc_free(op->constraint);
1016 vpop();
1018 cstr_free(&astr1);
1021 void asm_global_instr(void)
1023 CString astr;
1025 next();
1026 parse_asm_str(&astr);
1027 skip(')');
1028 /* NOTE: we do not eat the ';' so that we can restore the current
1029 token after the assembler parsing */
1030 if (tok != ';')
1031 expect("';'");
1033 #ifdef ASM_DEBUG
1034 printf("asm_global: \"%s\"\n", (char *)astr.data);
1035 #endif
1036 cur_text_section = text_section;
1037 ind = cur_text_section->data_offset;
1039 /* assemble the string with tcc internal assembler */
1040 tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
1042 cur_text_section->data_offset = ind;
1044 /* restore the current C token */
1045 next();
1047 cstr_free(&astr);