2 * GAS like assembler for TCC
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
24 ST_FUNC
int asm_get_local_label_name(TCCState
*s1
, unsigned int n
)
29 snprintf(buf
, sizeof(buf
), "L..%u", n
);
30 ts
= tok_alloc(buf
, strlen(buf
));
34 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
);
35 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
);
38 /* We do not use the C expression parser to handle symbols. Maybe the
39 C expression parser could be tweaked to do so. */
41 static void asm_expr_unary(TCCState
*s1
, ExprValue
*pe
)
51 n
= strtoul(p
, (char **)&p
, 0);
52 if (*p
== 'b' || *p
== 'f') {
53 /* backward or forward label */
54 label
= asm_get_local_label_name(s1
, n
);
55 sym
= label_find(label
);
57 /* backward : find the last corresponding defined label */
58 if (sym
&& sym
->r
== 0)
61 tcc_error("local label '%d' not found backward", n
);
65 /* if the last label is defined, then define a new one */
66 sym
= label_push(&s1
->asm_labels
, label
, 0);
67 sym
->type
.t
= VT_STATIC
| VT_VOID
| VT_EXTERN
;
73 } else if (*p
== '\0') {
78 tcc_error("invalid number syntax");
84 asm_expr_unary(s1
, pe
);
90 asm_expr_unary(s1
, pe
);
92 tcc_error("invalid operation with label");
114 sym_dot
.type
.t
= VT_VOID
| VT_STATIC
;
115 sym_dot
.r
= cur_text_section
->sh_num
;
120 if (tok
>= TOK_IDENT
) {
121 /* label case : if the label was not found, add one */
122 sym
= label_find(tok
);
124 sym
= label_push(&s1
->asm_labels
, tok
, 0);
125 /* NOTE: by default, the symbol is global */
126 sym
->type
.t
= VT_VOID
| VT_EXTERN
;
128 if (sym
->r
== SHN_ABS
) {
129 /* if absolute symbol, no need to put a symbol value */
140 tcc_error("bad expression syntax [%s]", get_tok_str(tok
, &tokc
));
146 static void asm_expr_prod(TCCState
*s1
, ExprValue
*pe
)
151 asm_expr_unary(s1
, pe
);
154 if (op
!= '*' && op
!= '/' && op
!= '%' &&
155 op
!= TOK_SHL
&& op
!= TOK_SAR
)
158 asm_expr_unary(s1
, &e2
);
159 if (pe
->sym
|| e2
.sym
)
160 tcc_error("invalid operation with label");
168 tcc_error("division by zero");
188 static void asm_expr_logic(TCCState
*s1
, ExprValue
*pe
)
193 asm_expr_prod(s1
, pe
);
196 if (op
!= '&' && op
!= '|' && op
!= '^')
199 asm_expr_prod(s1
, &e2
);
200 if (pe
->sym
|| e2
.sym
)
201 tcc_error("invalid operation with label");
217 static inline void asm_expr_sum(TCCState
*s1
, ExprValue
*pe
)
222 asm_expr_logic(s1
, pe
);
225 if (op
!= '+' && op
!= '-')
228 asm_expr_logic(s1
, &e2
);
230 if (pe
->sym
!= NULL
&& e2
.sym
!= NULL
)
231 goto cannot_relocate
;
233 if (pe
->sym
== NULL
&& e2
.sym
!= NULL
)
237 /* NOTE: we are less powerful than gas in that case
238 because we store only one symbol in the expression */
241 } else if (pe
->sym
== e2
.sym
) {
243 pe
->sym
= NULL
; /* same symbols can be subtracted to NULL */
244 } else if (pe
->sym
&& pe
->sym
->r
== e2
.sym
->r
&& pe
->sym
->r
!= 0) {
245 /* we also accept defined symbols in the same section */
246 pe
->v
+= pe
->sym
->jnext
- e2
.sym
->jnext
;
248 } else if (e2
.sym
->r
== cur_text_section
->sh_num
) {
249 /* When subtracting a defined symbol in current section
250 this actually makes the value PC-relative. */
251 pe
->v
-= e2
.sym
->jnext
- ind
- 4;
256 tcc_error("invalid operation with label");
262 static inline void asm_expr_cmp(TCCState
*s1
, ExprValue
*pe
)
267 asm_expr_sum(s1
, pe
);
270 if (op
!= TOK_EQ
&& op
!= TOK_NE
271 && (op
> TOK_GT
|| op
< TOK_ULE
))
274 asm_expr_sum(s1
, &e2
);
275 if (pe
->sym
|| e2
.sym
)
276 tcc_error("invalid operation with label");
279 pe
->v
= pe
->v
== e2
.v
;
282 pe
->v
= pe
->v
!= e2
.v
;
285 pe
->v
= (int64_t)pe
->v
< (int64_t)e2
.v
;
288 pe
->v
= (int64_t)pe
->v
>= (int64_t)e2
.v
;
291 pe
->v
= (int64_t)pe
->v
<= (int64_t)e2
.v
;
294 pe
->v
= (int64_t)pe
->v
> (int64_t)e2
.v
;
299 /* GAS compare results are -1/0 not 1/0. */
300 pe
->v
= -(int64_t)pe
->v
;
304 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
)
306 asm_expr_cmp(s1
, pe
);
309 ST_FUNC
int asm_int_expr(TCCState
*s1
)
318 /* NOTE: the same name space as C labels is used to avoid using too
319 much memory when storing labels in TokenStrings */
320 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
,
321 int sh_num
, int value
)
325 sym
= label_find(label
);
327 /* A VT_EXTERN symbol, even if it has a section is considered
328 overridable. This is how we "define" .set targets. Real
329 definitions won't have VT_EXTERN set. */
330 if (sym
->r
&& !(sym
->type
.t
& VT_EXTERN
)) {
331 /* the label is already defined */
333 tcc_error("assembler label '%s' already defined",
334 get_tok_str(label
, NULL
));
336 /* redefinition of local labels is possible */
342 sym
= label_push(&s1
->asm_labels
, label
, 0);
343 /* If we need a symbol to hold a value, mark it as
344 tentative only (for .set). If this is for a real label
345 we'll remove VT_EXTERN. */
346 sym
->type
.t
= VT_STATIC
| VT_VOID
| VT_EXTERN
;
353 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
)
355 return asm_new_label1(s1
, label
, is_local
, cur_text_section
->sh_num
, ind
);
358 /* Set the value of LABEL to that of some expression (possibly
359 involving other symbols). LABEL can be overwritten later still. */
360 static Sym
* set_symbol(TCCState
*s1
, int label
)
370 return asm_new_label1(s1
, label
, 0, e
.sym
? e
.sym
->r
: SHN_ABS
, n
);
373 static void asm_free_labels(TCCState
*st
)
378 for(s
= st
->asm_labels
; s
!= NULL
; s
= s1
) {
380 /* define symbol value in object file */
381 s
->type
.t
&= ~VT_EXTERN
;
386 sec
= st
->sections
[s
->r
];
387 put_extern_sym2(s
, sec
, s
->jnext
, 0, 0);
390 table_ident
[s
->v
- TOK_IDENT
]->sym_label
= NULL
;
393 st
->asm_labels
= NULL
;
396 static void use_section1(TCCState
*s1
, Section
*sec
)
398 cur_text_section
->data_offset
= ind
;
399 cur_text_section
= sec
;
400 ind
= cur_text_section
->data_offset
;
403 static void use_section(TCCState
*s1
, const char *name
)
406 sec
= find_section(s1
, name
);
407 use_section1(s1
, sec
);
410 static void push_section(TCCState
*s1
, const char *name
)
412 Section
*sec
= find_section(s1
, name
);
413 sec
->prev
= cur_text_section
;
414 use_section1(s1
, sec
);
417 static void pop_section(TCCState
*s1
)
419 Section
*prev
= cur_text_section
->prev
;
421 tcc_error(".popsection without .pushsection");
422 cur_text_section
->prev
= NULL
;
423 use_section1(s1
, prev
);
426 static void asm_parse_directive(TCCState
*s1
)
428 int n
, offset
, v
, size
, tok1
;
432 /* assembler directive */
433 sec
= cur_text_section
;
435 case TOK_ASMDIR_align
:
436 case TOK_ASMDIR_balign
:
437 case TOK_ASMDIR_p2align
:
438 case TOK_ASMDIR_skip
:
439 case TOK_ASMDIR_space
:
442 n
= asm_int_expr(s1
);
443 if (tok1
== TOK_ASMDIR_p2align
)
446 tcc_error("invalid p2align, must be between 0 and 30");
448 tok1
= TOK_ASMDIR_align
;
450 if (tok1
== TOK_ASMDIR_align
|| tok1
== TOK_ASMDIR_balign
) {
451 if (n
< 0 || (n
& (n
-1)) != 0)
452 tcc_error("alignment must be a positive power of two");
453 offset
= (ind
+ n
- 1) & -n
;
455 /* the section must have a compatible alignment */
456 if (sec
->sh_addralign
< n
)
457 sec
->sh_addralign
= n
;
466 v
= asm_int_expr(s1
);
469 if (sec
->sh_type
!= SHT_NOBITS
) {
470 sec
->data_offset
= ind
;
471 ptr
= section_ptr_add(sec
, size
);
472 memset(ptr
, v
, size
);
476 case TOK_ASMDIR_quad
:
477 #ifdef TCC_TARGET_X86_64
487 if (tok
!= TOK_PPNUM
) {
489 tcc_error("64 bit constant");
491 vl
= strtoll(p
, (char **)&p
, 0);
495 if (sec
->sh_type
!= SHT_NOBITS
) {
496 /* XXX: endianness */
508 case TOK_ASMDIR_byte
:
511 case TOK_ASMDIR_word
:
512 case TOK_ASMDIR_short
:
515 case TOK_ASMDIR_long
:
523 if (sec
->sh_type
!= SHT_NOBITS
) {
526 #ifdef TCC_TARGET_X86_64
527 } else if (size
== 8) {
546 case TOK_ASMDIR_fill
:
548 int repeat
, size
, val
, i
, j
;
549 uint8_t repeat_buf
[8];
551 repeat
= asm_int_expr(s1
);
553 tcc_error("repeat < 0; .fill ignored");
560 size
= asm_int_expr(s1
);
562 tcc_error("size < 0; .fill ignored");
569 val
= asm_int_expr(s1
);
572 /* XXX: endianness */
574 repeat_buf
[1] = val
>> 8;
575 repeat_buf
[2] = val
>> 16;
576 repeat_buf
[3] = val
>> 24;
581 for(i
= 0; i
< repeat
; i
++) {
582 for(j
= 0; j
< size
; j
++) {
588 case TOK_ASMDIR_rept
:
591 TokenString
*init_str
;
592 ParseState saved_parse_state
= {0};
594 repeat
= asm_int_expr(s1
);
595 init_str
= tok_str_alloc();
597 while ((tok
!= TOK_ASMDIR_endr
) && (tok
!= CH_EOF
)) {
598 tok_str_add_tok(init_str
);
601 if (tok
== CH_EOF
) tcc_error("we at end of file, .endr not found");
603 tok_str_add(init_str
, -1);
604 tok_str_add(init_str
, 0);
605 save_parse_state(&saved_parse_state
);
606 begin_macro(init_str
, 1);
607 while (repeat
-- > 0) {
608 tcc_assemble_internal(s1
, (parse_flags
& PARSE_FLAG_PREPROCESS
));
609 macro_ptr
= init_str
->str
;
612 restore_parse_state(&saved_parse_state
);
623 if (e
.sym
->r
!= cur_text_section
->sh_num
)
624 expect("constant or same-section symbol");
628 tcc_error("attempt to .org backwards");
638 /* Also accept '.set stuff', but don't do anything with this.
639 It's used in GAS to set various features like '.set mips16'. */
641 set_symbol(s1
, tok1
);
643 case TOK_ASMDIR_globl
:
644 case TOK_ASMDIR_global
:
645 case TOK_ASMDIR_weak
:
646 case TOK_ASMDIR_hidden
:
652 sym
= label_find(tok
);
654 sym
= label_push(&s1
->asm_labels
, tok
, 0);
655 sym
->type
.t
= VT_VOID
| VT_EXTERN
;
657 if (tok1
!= TOK_ASMDIR_hidden
)
658 sym
->type
.t
&= ~VT_STATIC
;
659 if (tok1
== TOK_ASMDIR_weak
)
660 sym
->type
.t
|= VT_WEAK
;
661 else if (tok1
== TOK_ASMDIR_hidden
)
662 sym
->type
.t
|= STV_HIDDEN
<< VT_VIS_SHIFT
;
664 } while (tok
== ',');
666 case TOK_ASMDIR_string
:
667 case TOK_ASMDIR_ascii
:
668 case TOK_ASMDIR_asciz
:
677 expect("string constant");
679 size
= tokc
.str
.size
;
680 if (t
== TOK_ASMDIR_ascii
&& size
> 0)
682 for(i
= 0; i
< size
; i
++)
687 } else if (tok
!= TOK_STR
) {
693 case TOK_ASMDIR_text
:
694 case TOK_ASMDIR_data
:
701 if (tok
!= ';' && tok
!= TOK_LINEFEED
) {
702 n
= asm_int_expr(s1
);
706 sprintf(sname
, "%s%d", get_tok_str(tok1
, NULL
), n
);
708 sprintf(sname
, "%s", get_tok_str(tok1
, NULL
));
709 use_section(s1
, sname
);
712 case TOK_ASMDIR_file
:
720 pstrcat(filename
, sizeof(filename
), tokc
.str
.data
);
722 pstrcat(filename
, sizeof(filename
), get_tok_str(tok
, NULL
));
724 if (s1
->warn_unsupported
)
725 tcc_warning("ignoring .file %s", filename
);
730 case TOK_ASMDIR_ident
:
738 pstrcat(ident
, sizeof(ident
), tokc
.str
.data
);
740 pstrcat(ident
, sizeof(ident
), get_tok_str(tok
, NULL
));
742 if (s1
->warn_unsupported
)
743 tcc_warning("ignoring .ident %s", ident
);
748 case TOK_ASMDIR_size
:
753 sym
= label_find(tok
);
755 tcc_error("label not found: %s", get_tok_str(tok
, NULL
));
758 /* XXX .size name,label2-label1 */
759 if (s1
->warn_unsupported
)
760 tcc_warning("ignoring .size %s,*", get_tok_str(tok
, NULL
));
764 while (tok
!= TOK_LINEFEED
&& tok
!= ';' && tok
!= CH_EOF
) {
769 case TOK_ASMDIR_type
:
775 sym
= label_find(tok
);
777 sym
= label_push(&s1
->asm_labels
, tok
, 0);
778 sym
->type
.t
= VT_VOID
| VT_EXTERN
;
783 if (tok
== TOK_STR
) {
784 newtype
= tokc
.str
.data
;
786 if (tok
== '@' || tok
== '%')
788 newtype
= get_tok_str(tok
, NULL
);
791 if (!strcmp(newtype
, "function") || !strcmp(newtype
, "STT_FUNC")) {
792 sym
->type
.t
= (sym
->type
.t
& ~VT_BTYPE
) | VT_FUNC
;
794 else if (s1
->warn_unsupported
)
795 tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
796 get_tok_str(sym
->v
, NULL
), sym
->type
.t
, newtype
);
801 case TOK_ASMDIR_pushsection
:
802 case TOK_ASMDIR_section
:
805 int old_nb_section
= s1
->nb_sections
;
808 /* XXX: support more options */
811 while (tok
!= ';' && tok
!= TOK_LINEFEED
&& tok
!= ',') {
813 pstrcat(sname
, sizeof(sname
), tokc
.str
.data
);
815 pstrcat(sname
, sizeof(sname
), get_tok_str(tok
, NULL
));
819 /* skip section options */
822 expect("string constant");
826 if (tok
== '@' || tok
== '%')
831 last_text_section
= cur_text_section
;
832 if (tok1
== TOK_ASMDIR_section
)
833 use_section(s1
, sname
);
835 push_section(s1
, sname
);
836 /* If we just allocated a new section reset its alignment to
837 1. new_section normally acts for GCC compatibility and
838 sets alignment to PTR_SIZE. The assembler behaves different. */
839 if (old_nb_section
!= s1
->nb_sections
)
840 cur_text_section
->sh_addralign
= 1;
843 case TOK_ASMDIR_previous
:
847 if (!last_text_section
)
848 tcc_error("no previous section referenced");
849 sec
= cur_text_section
;
850 use_section1(s1
, last_text_section
);
851 last_text_section
= sec
;
854 case TOK_ASMDIR_popsection
:
858 #ifdef TCC_TARGET_I386
859 case TOK_ASMDIR_code16
:
865 case TOK_ASMDIR_code32
:
872 #ifdef TCC_TARGET_X86_64
873 /* added for compatibility with GAS */
874 case TOK_ASMDIR_code64
:
879 tcc_error("unknown assembler directive '.%s'", get_tok_str(tok
, NULL
));
885 /* assemble a file */
886 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
)
890 /* XXX: undefine C labels */
892 ch
= file
->buf_ptr
[0];
893 tok_flags
= TOK_FLAG_BOL
| TOK_FLAG_BOF
;
894 parse_flags
= PARSE_FLAG_ASM_FILE
| PARSE_FLAG_TOK_STR
;
896 parse_flags
|= PARSE_FLAG_PREPROCESS
;
901 parse_flags
|= PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
904 /* horrible gas comment */
905 while (tok
!= TOK_LINEFEED
)
907 } else if (tok
>= TOK_ASMDIR_FIRST
&& tok
<= TOK_ASMDIR_LAST
) {
908 asm_parse_directive(s1
);
909 } else if (tok
== TOK_PPNUM
) {
914 n
= strtoul(p
, (char **)&p
, 10);
917 /* new local label */
918 sym
= asm_new_label(s1
, asm_get_local_label_name(s1
, n
), 1);
919 /* Remove the marker for tentative definitions. */
920 sym
->type
.t
&= ~VT_EXTERN
;
924 } else if (tok
>= TOK_IDENT
) {
925 /* instruction or label */
929 /* handle "extern void vide(void); __asm__("vide: ret");" as
930 "__asm__("globl vide\nvide: ret");" */
931 Sym
*sym
= sym_find(opcode
);
932 if (sym
&& (sym
->type
.t
& VT_EXTERN
) && nocode_wanted
) {
933 sym
= label_find(opcode
);
935 sym
= label_push(&s1
->asm_labels
, opcode
, 0);
936 sym
->type
.t
= VT_VOID
| VT_EXTERN
;
940 sym
= asm_new_label(s1
, opcode
, 0);
941 sym
->type
.t
&= ~VT_EXTERN
;
944 } else if (tok
== '=') {
945 set_symbol(s1
, opcode
);
948 asm_opcode(s1
, opcode
);
952 if (tok
!= ';' && tok
!= TOK_LINEFEED
){
953 expect("end of line");
955 parse_flags
&= ~PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
964 /* Assemble the current file */
965 ST_FUNC
int tcc_assemble(TCCState
*s1
, int do_preprocess
)
970 preprocess_start(s1
);
972 /* default section is text */
973 cur_text_section
= text_section
;
974 ind
= cur_text_section
->data_offset
;
976 define_start
= define_stack
;
978 /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
979 symbols can be safely used */
980 put_elf_sym(symtab_section
, 0, 0,
981 ELFW(ST_INFO
)(STB_LOCAL
, STT_FILE
), 0,
982 SHN_ABS
, file
->filename
);
984 ret
= tcc_assemble_internal(s1
, do_preprocess
);
986 cur_text_section
->data_offset
= ind
;
988 free_defines(define_start
);
993 /********************************************************************/
994 /* GCC inline asm support */
996 /* assemble the string 'str' in the current C compilation unit without
997 C preprocessing. NOTE: str is modified by modifying the '\0' at the
999 static void tcc_assemble_inline(TCCState
*s1
, char *str
, int len
)
1001 int saved_parse_flags
;
1002 const int *saved_macro_ptr
;
1004 saved_parse_flags
= parse_flags
;
1005 saved_macro_ptr
= macro_ptr
;
1007 tcc_open_bf(s1
, ":asm:", len
);
1008 memcpy(file
->buffer
, str
, len
);
1011 tcc_assemble_internal(s1
, 0);
1014 parse_flags
= saved_parse_flags
;
1015 macro_ptr
= saved_macro_ptr
;
1018 /* find a constraint by its number or id (gcc 3 extended
1019 syntax). return -1 if not found. Return in *pp in char after the
1021 ST_FUNC
int find_constraint(ASMOperand
*operands
, int nb_operands
,
1022 const char *name
, const char **pp
)
1030 while (isnum(*name
)) {
1031 index
= (index
* 10) + (*name
) - '0';
1034 if ((unsigned)index
>= nb_operands
)
1036 } else if (*name
== '[') {
1038 p
= strchr(name
, ']');
1040 ts
= tok_alloc(name
, p
- name
);
1041 for(index
= 0; index
< nb_operands
; index
++) {
1042 if (operands
[index
].id
== ts
->tok
)
1059 static void subst_asm_operands(ASMOperand
*operands
, int nb_operands
,
1061 CString
*out_str
, CString
*in_str
)
1063 int c
, index
, modifier
;
1078 if (*str
== 'c' || *str
== 'n' ||
1079 *str
== 'b' || *str
== 'w' || *str
== 'h' || *str
== 'k' ||
1081 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
1082 and make literal operands not be decorated with '$'. */
1085 index
= find_constraint(operands
, nb_operands
, str
, &str
);
1087 tcc_error("invalid operand reference after %%");
1088 op
= &operands
[index
];
1092 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& op
->is_memory
)
1095 subst_asm_operand(out_str
, &sv
, modifier
);
1098 cstr_ccat(out_str
, c
);
1106 static void parse_asm_operands(ASMOperand
*operands
, int *nb_operands_ptr
,
1113 nb_operands
= *nb_operands_ptr
;
1116 if (nb_operands
>= MAX_ASM_OPERANDS
)
1117 tcc_error("too many asm operands");
1118 op
= &operands
[nb_operands
++];
1122 if (tok
< TOK_IDENT
)
1123 expect("identifier");
1128 parse_mult_str(&astr
, "string constant");
1129 op
->constraint
= tcc_malloc(astr
.size
);
1130 strcpy(op
->constraint
, astr
.data
);
1135 if (!(vtop
->type
.t
& VT_ARRAY
))
1138 /* we want to avoid LLOCAL case, except when the 'm'
1139 constraint is used. Note that it may come from
1140 register storage, so we need to convert (reg)
1142 if ((vtop
->r
& VT_LVAL
) &&
1143 ((vtop
->r
& VT_VALMASK
) == VT_LLOCAL
||
1144 (vtop
->r
& VT_VALMASK
) < VT_CONST
) &&
1145 !strchr(op
->constraint
, 'm')) {
1157 *nb_operands_ptr
= nb_operands
;
1161 /* parse the GCC asm() instruction */
1162 ST_FUNC
void asm_instr(void)
1164 CString astr
, astr1
;
1165 ASMOperand operands
[MAX_ASM_OPERANDS
];
1166 int nb_outputs
, nb_operands
, i
, must_subst
, out_reg
;
1167 uint8_t clobber_regs
[NB_ASM_REGS
];
1170 /* since we always generate the asm() instruction, we can ignore
1172 if (tok
== TOK_VOLATILE1
|| tok
== TOK_VOLATILE2
|| tok
== TOK_VOLATILE3
) {
1175 parse_asm_str(&astr
);
1179 memset(clobber_regs
, 0, sizeof(clobber_regs
));
1184 parse_asm_operands(operands
, &nb_operands
, 1);
1185 nb_outputs
= nb_operands
;
1190 parse_asm_operands(operands
, &nb_operands
, 0);
1193 /* XXX: handle registers */
1197 expect("string constant");
1198 asm_clobber(clobber_regs
, tokc
.str
.data
);
1211 /* NOTE: we do not eat the ';' so that we can restore the current
1212 token after the assembler parsing */
1216 /* save all values in the memory */
1219 /* compute constraints */
1220 asm_compute_constraints(operands
, nb_operands
, nb_outputs
,
1221 clobber_regs
, &out_reg
);
1223 /* substitute the operands in the asm string. No substitution is
1224 done if no operands (GCC behaviour) */
1226 printf("asm: \"%s\"\n", (char *)astr
.data
);
1229 subst_asm_operands(operands
, nb_operands
, nb_outputs
, &astr1
, &astr
);
1235 printf("subst_asm: \"%s\"\n", (char *)astr1
.data
);
1238 /* generate loads */
1239 asm_gen_code(operands
, nb_operands
, nb_outputs
, 0,
1240 clobber_regs
, out_reg
);
1242 /* assemble the string with tcc internal assembler */
1243 tcc_assemble_inline(tcc_state
, astr1
.data
, astr1
.size
- 1);
1245 /* restore the current C token */
1248 /* store the output values if needed */
1249 asm_gen_code(operands
, nb_operands
, nb_outputs
, 1,
1250 clobber_regs
, out_reg
);
1252 /* free everything */
1253 for(i
=0;i
<nb_operands
;i
++) {
1256 tcc_free(op
->constraint
);
1262 ST_FUNC
void asm_global_instr(void)
1267 parse_asm_str(&astr
);
1269 /* NOTE: we do not eat the ';' so that we can restore the current
1270 token after the assembler parsing */
1275 printf("asm_global: \"%s\"\n", (char *)astr
.data
);
1277 cur_text_section
= text_section
;
1278 ind
= cur_text_section
->data_offset
;
1280 /* assemble the string with tcc internal assembler */
1281 tcc_assemble_inline(tcc_state
, astr
.data
, astr
.size
- 1);
1283 cur_text_section
->data_offset
= ind
;
1285 /* restore the current C token */
1290 #endif /* CONFIG_TCC_ASM */