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
25 static Section
*last_text_section
; /* to handle .previous asm directive */
27 ST_FUNC
int asm_get_local_label_name(TCCState
*s1
, unsigned int n
)
32 snprintf(buf
, sizeof(buf
), "L..%u", n
);
33 ts
= tok_alloc(buf
, strlen(buf
));
37 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
);
38 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
);
39 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
, int sh_num
, int value
);
41 static Sym
*asm_label_find(int v
)
43 Sym
*sym
= sym_find(v
);
44 while (sym
&& sym
->sym_scope
&& !(sym
->type
.t
& VT_STATIC
))
49 static Sym
*asm_label_push(int v
)
51 /* We always add VT_EXTERN, for sym definition that's tentative
52 (for .set, removed for real defs), for mere references it's correct
54 return global_identifier_push(v
, VT_ASM
| VT_EXTERN
| VT_STATIC
, 0);
57 /* Return a symbol we can use inside the assembler, having name NAME.
58 Symbols from asm and C source share a namespace. If we generate
59 an asm symbol it's also a (file-global) C symbol, but it's
60 either not accessible by name (like "L.123"), or its type information
61 is such that it's not usable without a proper C declaration.
63 Sometimes we need symbols accessible by name from asm, which
64 are anonymous in C, in this case CSYM can be used to transfer
65 all information from that symbol to the (possibly newly created)
67 ST_FUNC Sym
* get_asm_sym(int name
, Sym
*csym
)
69 Sym
*sym
= asm_label_find(name
);
71 sym
= asm_label_push(name
);
78 static Sym
* asm_section_sym(TCCState
*s1
, Section
*sec
)
81 int label
= tok_alloc(buf
,
82 snprintf(buf
, sizeof buf
, "L.%s", sec
->name
)
84 Sym
*sym
= asm_label_find(label
);
85 return sym
? sym
: asm_new_label1(s1
, label
, 1, sec
->sh_num
, 0);
88 /* We do not use the C expression parser to handle symbols. Maybe the
89 C expression parser could be tweaked to do so. */
91 static void asm_expr_unary(TCCState
*s1
, ExprValue
*pe
)
101 n
= strtoull(p
, (char **)&p
, 0);
102 if (*p
== 'b' || *p
== 'f') {
103 /* backward or forward label */
104 label
= asm_get_local_label_name(s1
, n
);
105 sym
= asm_label_find(label
);
107 /* backward : find the last corresponding defined label */
108 if (sym
&& (!sym
->c
|| elfsym(sym
)->st_shndx
== SHN_UNDEF
))
111 tcc_error("local label '%d' not found backward", (int)n
);
114 if (!sym
|| (sym
->c
&& elfsym(sym
)->st_shndx
!= SHN_UNDEF
)) {
115 /* if the last label is defined, then define a new one */
116 sym
= asm_label_push(label
);
122 } else if (*p
== '\0') {
127 tcc_error("invalid number syntax");
133 asm_expr_unary(s1
, pe
);
139 asm_expr_unary(s1
, pe
);
141 tcc_error("invalid operation with label");
161 pe
->sym
= asm_section_sym(s1
, cur_text_section
);
166 if (tok
>= TOK_IDENT
) {
168 /* label case : if the label was not found, add one */
169 sym
= get_asm_sym(tok
, NULL
);
171 if (esym
&& esym
->st_shndx
== SHN_ABS
) {
172 /* if absolute symbol, no need to put a symbol value */
173 pe
->v
= esym
->st_value
;
183 tcc_error("bad expression syntax [%s]", get_tok_str(tok
, &tokc
));
189 static void asm_expr_prod(TCCState
*s1
, ExprValue
*pe
)
194 asm_expr_unary(s1
, pe
);
197 if (op
!= '*' && op
!= '/' && op
!= '%' &&
198 op
!= TOK_SHL
&& op
!= TOK_SAR
)
201 asm_expr_unary(s1
, &e2
);
202 if (pe
->sym
|| e2
.sym
)
203 tcc_error("invalid operation with label");
211 tcc_error("division by zero");
231 static void asm_expr_logic(TCCState
*s1
, ExprValue
*pe
)
236 asm_expr_prod(s1
, pe
);
239 if (op
!= '&' && op
!= '|' && op
!= '^')
242 asm_expr_prod(s1
, &e2
);
243 if (pe
->sym
|| e2
.sym
)
244 tcc_error("invalid operation with label");
260 static inline void asm_expr_sum(TCCState
*s1
, ExprValue
*pe
)
265 asm_expr_logic(s1
, pe
);
268 if (op
!= '+' && op
!= '-')
271 asm_expr_logic(s1
, &e2
);
273 if (pe
->sym
!= NULL
&& e2
.sym
!= NULL
)
274 goto cannot_relocate
;
276 if (pe
->sym
== NULL
&& e2
.sym
!= NULL
)
280 /* NOTE: we are less powerful than gas in that case
281 because we store only one symbol in the expression */
284 } else if (pe
->sym
== e2
.sym
) {
286 pe
->sym
= NULL
; /* same symbols can be subtracted to NULL */
288 ElfSym
*esym1
, *esym2
;
289 esym1
= elfsym(pe
->sym
);
290 esym2
= elfsym(e2
.sym
);
291 if (esym1
&& esym1
->st_shndx
== esym2
->st_shndx
292 && esym1
->st_shndx
!= SHN_UNDEF
) {
293 /* we also accept defined symbols in the same section */
294 pe
->v
+= esym1
->st_value
- esym2
->st_value
;
296 } else if (esym2
->st_shndx
== cur_text_section
->sh_num
) {
297 /* When subtracting a defined symbol in current section
298 this actually makes the value PC-relative. */
299 pe
->v
-= esym2
->st_value
- ind
- 4;
304 tcc_error("invalid operation with label");
311 static inline void asm_expr_cmp(TCCState
*s1
, ExprValue
*pe
)
316 asm_expr_sum(s1
, pe
);
319 if (op
!= TOK_EQ
&& op
!= TOK_NE
320 && (op
> TOK_GT
|| op
< TOK_ULE
))
323 asm_expr_sum(s1
, &e2
);
324 if (pe
->sym
|| e2
.sym
)
325 tcc_error("invalid operation with label");
328 pe
->v
= pe
->v
== e2
.v
;
331 pe
->v
= pe
->v
!= e2
.v
;
334 pe
->v
= (int64_t)pe
->v
< (int64_t)e2
.v
;
337 pe
->v
= (int64_t)pe
->v
>= (int64_t)e2
.v
;
340 pe
->v
= (int64_t)pe
->v
<= (int64_t)e2
.v
;
343 pe
->v
= (int64_t)pe
->v
> (int64_t)e2
.v
;
348 /* GAS compare results are -1/0 not 1/0. */
349 pe
->v
= -(int64_t)pe
->v
;
353 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
)
355 asm_expr_cmp(s1
, pe
);
358 ST_FUNC
int asm_int_expr(TCCState
*s1
)
367 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
,
368 int sh_num
, int value
)
373 sym
= asm_label_find(label
);
376 /* A VT_EXTERN symbol, even if it has a section is considered
377 overridable. This is how we "define" .set targets. Real
378 definitions won't have VT_EXTERN set. */
379 if (esym
&& esym
->st_shndx
!= SHN_UNDEF
) {
380 /* the label is already defined */
382 && (is_local
== 1 || (sym
->type
.t
& VT_EXTERN
)))
384 if (!(sym
->type
.t
& VT_EXTERN
))
385 tcc_error("assembler label '%s' already defined",
386 get_tok_str(label
, NULL
));
390 sym
= asm_label_push(label
);
393 put_extern_sym2(sym
, SHN_UNDEF
, 0, 0, 0);
395 esym
->st_shndx
= sh_num
;
396 esym
->st_value
= value
;
398 sym
->type
.t
&= ~VT_EXTERN
;
402 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
)
404 return asm_new_label1(s1
, label
, is_local
, cur_text_section
->sh_num
, ind
);
407 /* Set the value of LABEL to that of some expression (possibly
408 involving other symbols). LABEL can be overwritten later still. */
409 static Sym
* set_symbol(TCCState
*s1
, int label
)
418 esym
= elfsym(e
.sym
);
421 sym
= asm_new_label1(s1
, label
, 2, esym
? esym
->st_shndx
: SHN_ABS
, n
);
422 elfsym(sym
)->st_other
|= ST_ASM_SET
;
426 static void use_section1(TCCState
*s1
, Section
*sec
)
428 cur_text_section
->data_offset
= ind
;
429 cur_text_section
= sec
;
430 ind
= cur_text_section
->data_offset
;
433 static void use_section(TCCState
*s1
, const char *name
)
436 sec
= find_section(s1
, name
);
437 use_section1(s1
, sec
);
440 static void push_section(TCCState
*s1
, const char *name
)
442 Section
*sec
= find_section(s1
, name
);
443 sec
->prev
= cur_text_section
;
444 use_section1(s1
, sec
);
447 static void pop_section(TCCState
*s1
)
449 Section
*prev
= cur_text_section
->prev
;
451 tcc_error(".popsection without .pushsection");
452 cur_text_section
->prev
= NULL
;
453 use_section1(s1
, prev
);
456 static void asm_parse_directive(TCCState
*s1
, int global
)
458 int n
, offset
, v
, size
, tok1
;
462 /* assembler directive */
463 sec
= cur_text_section
;
465 case TOK_ASMDIR_align
:
466 case TOK_ASMDIR_balign
:
467 case TOK_ASMDIR_p2align
:
468 case TOK_ASMDIR_skip
:
469 case TOK_ASMDIR_space
:
472 n
= asm_int_expr(s1
);
473 if (tok1
== TOK_ASMDIR_p2align
)
476 tcc_error("invalid p2align, must be between 0 and 30");
478 tok1
= TOK_ASMDIR_align
;
480 if (tok1
== TOK_ASMDIR_align
|| tok1
== TOK_ASMDIR_balign
) {
481 if (n
< 0 || (n
& (n
-1)) != 0)
482 tcc_error("alignment must be a positive power of two");
483 offset
= (ind
+ n
- 1) & -n
;
485 /* the section must have a compatible alignment */
486 if (sec
->sh_addralign
< n
)
487 sec
->sh_addralign
= n
;
496 v
= asm_int_expr(s1
);
499 if (sec
->sh_type
!= SHT_NOBITS
) {
500 sec
->data_offset
= ind
;
501 ptr
= section_ptr_add(sec
, size
);
502 memset(ptr
, v
, size
);
506 case TOK_ASMDIR_quad
:
507 #ifdef TCC_TARGET_X86_64
517 if (tok
!= TOK_PPNUM
) {
519 tcc_error("64 bit constant");
521 vl
= strtoll(p
, (char **)&p
, 0);
525 if (sec
->sh_type
!= SHT_NOBITS
) {
526 /* XXX: endianness */
538 case TOK_ASMDIR_byte
:
541 case TOK_ASMDIR_word
:
542 case TOK_ASMDIR_short
:
545 case TOK_ASMDIR_long
:
553 if (sec
->sh_type
!= SHT_NOBITS
) {
556 #ifdef TCC_TARGET_X86_64
557 } else if (size
== 8) {
576 case TOK_ASMDIR_fill
:
578 int repeat
, size
, val
, i
, j
;
579 uint8_t repeat_buf
[8];
581 repeat
= asm_int_expr(s1
);
583 tcc_error("repeat < 0; .fill ignored");
590 size
= asm_int_expr(s1
);
592 tcc_error("size < 0; .fill ignored");
599 val
= asm_int_expr(s1
);
602 /* XXX: endianness */
604 repeat_buf
[1] = val
>> 8;
605 repeat_buf
[2] = val
>> 16;
606 repeat_buf
[3] = val
>> 24;
611 for(i
= 0; i
< repeat
; i
++) {
612 for(j
= 0; j
< size
; j
++) {
618 case TOK_ASMDIR_rept
:
621 TokenString
*init_str
;
623 repeat
= asm_int_expr(s1
);
624 init_str
= tok_str_alloc();
625 while (next(), tok
!= TOK_ASMDIR_endr
) {
627 tcc_error("we at end of file, .endr not found");
628 tok_str_add_tok(init_str
);
630 tok_str_add(init_str
, -1);
631 tok_str_add(init_str
, 0);
632 begin_macro(init_str
, 1);
633 while (repeat
-- > 0) {
634 tcc_assemble_internal(s1
, (parse_flags
& PARSE_FLAG_PREPROCESS
),
636 macro_ptr
= init_str
->str
;
650 esym
= elfsym(e
.sym
);
652 if (esym
->st_shndx
!= cur_text_section
->sh_num
)
653 expect("constant or same-section symbol");
657 tcc_error("attempt to .org backwards");
667 /* Also accept '.set stuff', but don't do anything with this.
668 It's used in GAS to set various features like '.set mips16'. */
670 set_symbol(s1
, tok1
);
672 case TOK_ASMDIR_globl
:
673 case TOK_ASMDIR_global
:
674 case TOK_ASMDIR_weak
:
675 case TOK_ASMDIR_hidden
:
680 sym
= get_asm_sym(tok
, NULL
);
681 if (tok1
!= TOK_ASMDIR_hidden
)
682 sym
->type
.t
&= ~VT_STATIC
;
683 if (tok1
== TOK_ASMDIR_weak
)
685 else if (tok1
== TOK_ASMDIR_hidden
)
686 sym
->a
.visibility
= STV_HIDDEN
;
689 } while (tok
== ',');
691 case TOK_ASMDIR_string
:
692 case TOK_ASMDIR_ascii
:
693 case TOK_ASMDIR_asciz
:
702 expect("string constant");
704 size
= tokc
.str
.size
;
705 if (t
== TOK_ASMDIR_ascii
&& size
> 0)
707 for(i
= 0; i
< size
; i
++)
712 } else if (tok
!= TOK_STR
) {
718 case TOK_ASMDIR_text
:
719 case TOK_ASMDIR_data
:
726 if (tok
!= ';' && tok
!= TOK_LINEFEED
) {
727 n
= asm_int_expr(s1
);
731 sprintf(sname
, "%s%d", get_tok_str(tok1
, NULL
), n
);
733 sprintf(sname
, "%s", get_tok_str(tok1
, NULL
));
734 use_section(s1
, sname
);
737 case TOK_ASMDIR_file
:
745 pstrcat(filename
, sizeof(filename
), tokc
.str
.data
);
747 pstrcat(filename
, sizeof(filename
), get_tok_str(tok
, NULL
));
749 if (s1
->warn_unsupported
)
750 tcc_warning("ignoring .file %s", filename
);
755 case TOK_ASMDIR_ident
:
763 pstrcat(ident
, sizeof(ident
), tokc
.str
.data
);
765 pstrcat(ident
, sizeof(ident
), get_tok_str(tok
, NULL
));
767 if (s1
->warn_unsupported
)
768 tcc_warning("ignoring .ident %s", ident
);
773 case TOK_ASMDIR_size
:
778 sym
= asm_label_find(tok
);
780 tcc_error("label not found: %s", get_tok_str(tok
, NULL
));
783 /* XXX .size name,label2-label1 */
784 if (s1
->warn_unsupported
)
785 tcc_warning("ignoring .size %s,*", get_tok_str(tok
, NULL
));
789 while (tok
!= TOK_LINEFEED
&& tok
!= ';' && tok
!= CH_EOF
) {
794 case TOK_ASMDIR_type
:
800 sym
= get_asm_sym(tok
, NULL
);
803 if (tok
== TOK_STR
) {
804 newtype
= tokc
.str
.data
;
806 if (tok
== '@' || tok
== '%')
808 newtype
= get_tok_str(tok
, NULL
);
811 if (!strcmp(newtype
, "function") || !strcmp(newtype
, "STT_FUNC")) {
812 sym
->type
.t
= (sym
->type
.t
& ~VT_BTYPE
) | VT_FUNC
;
814 else if (s1
->warn_unsupported
)
815 tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
816 get_tok_str(sym
->v
, NULL
), sym
->type
.t
, newtype
);
821 case TOK_ASMDIR_pushsection
:
822 case TOK_ASMDIR_section
:
825 int old_nb_section
= s1
->nb_sections
;
828 /* XXX: support more options */
831 while (tok
!= ';' && tok
!= TOK_LINEFEED
&& tok
!= ',') {
833 pstrcat(sname
, sizeof(sname
), tokc
.str
.data
);
835 pstrcat(sname
, sizeof(sname
), get_tok_str(tok
, NULL
));
839 /* skip section options */
842 expect("string constant");
846 if (tok
== '@' || tok
== '%')
851 last_text_section
= cur_text_section
;
852 if (tok1
== TOK_ASMDIR_section
)
853 use_section(s1
, sname
);
855 push_section(s1
, sname
);
856 /* If we just allocated a new section reset its alignment to
857 1. new_section normally acts for GCC compatibility and
858 sets alignment to PTR_SIZE. The assembler behaves different. */
859 if (old_nb_section
!= s1
->nb_sections
)
860 cur_text_section
->sh_addralign
= 1;
863 case TOK_ASMDIR_previous
:
867 if (!last_text_section
)
868 tcc_error("no previous section referenced");
869 sec
= cur_text_section
;
870 use_section1(s1
, last_text_section
);
871 last_text_section
= sec
;
874 case TOK_ASMDIR_popsection
:
878 #ifdef TCC_TARGET_I386
879 case TOK_ASMDIR_code16
:
885 case TOK_ASMDIR_code32
:
892 #ifdef TCC_TARGET_X86_64
893 /* added for compatibility with GAS */
894 case TOK_ASMDIR_code64
:
899 tcc_error("unknown assembler directive '.%s'", get_tok_str(tok
, NULL
));
905 /* assemble a file */
906 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
)
909 int saved_parse_flags
= parse_flags
;
911 parse_flags
= PARSE_FLAG_ASM_FILE
| PARSE_FLAG_TOK_STR
;
913 parse_flags
|= PARSE_FLAG_PREPROCESS
;
918 parse_flags
|= PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
921 /* horrible gas comment */
922 while (tok
!= TOK_LINEFEED
)
924 } else if (tok
>= TOK_ASMDIR_FIRST
&& tok
<= TOK_ASMDIR_LAST
) {
925 asm_parse_directive(s1
, global
);
926 } else if (tok
== TOK_PPNUM
) {
930 n
= strtoul(p
, (char **)&p
, 10);
933 /* new local label */
934 asm_new_label(s1
, asm_get_local_label_name(s1
, n
), 1);
938 } else if (tok
>= TOK_IDENT
) {
939 /* instruction or label */
944 asm_new_label(s1
, opcode
, 0);
947 } else if (tok
== '=') {
948 set_symbol(s1
, opcode
);
951 asm_opcode(s1
, opcode
);
955 if (tok
!= ';' && tok
!= TOK_LINEFEED
)
956 expect("end of line");
957 parse_flags
&= ~PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
960 parse_flags
= saved_parse_flags
;
964 /* Assemble the current file */
965 ST_FUNC
int tcc_assemble(TCCState
*s1
, int do_preprocess
)
969 /* default section is text */
970 cur_text_section
= text_section
;
971 ind
= cur_text_section
->data_offset
;
973 ret
= tcc_assemble_internal(s1
, do_preprocess
, 1);
974 cur_text_section
->data_offset
= ind
;
979 /********************************************************************/
980 /* GCC inline asm support */
982 /* assemble the string 'str' in the current C compilation unit without
983 C preprocessing. NOTE: str is modified by modifying the '\0' at the
985 static void tcc_assemble_inline(TCCState
*s1
, char *str
, int len
, int global
)
987 const int *saved_macro_ptr
= macro_ptr
;
988 int dotid
= set_idnum('.', IS_ID
);
990 tcc_open_bf(s1
, ":asm:", len
);
991 memcpy(file
->buffer
, str
, len
);
993 tcc_assemble_internal(s1
, 0, global
);
996 set_idnum('.', dotid
);
997 macro_ptr
= saved_macro_ptr
;
1000 /* find a constraint by its number or id (gcc 3 extended
1001 syntax). return -1 if not found. Return in *pp in char after the
1003 ST_FUNC
int find_constraint(ASMOperand
*operands
, int nb_operands
,
1004 const char *name
, const char **pp
)
1012 while (isnum(*name
)) {
1013 index
= (index
* 10) + (*name
) - '0';
1016 if ((unsigned)index
>= nb_operands
)
1018 } else if (*name
== '[') {
1020 p
= strchr(name
, ']');
1022 ts
= tok_alloc(name
, p
- name
);
1023 for(index
= 0; index
< nb_operands
; index
++) {
1024 if (operands
[index
].id
== ts
->tok
)
1041 static void subst_asm_operands(ASMOperand
*operands
, int nb_operands
,
1042 CString
*out_str
, CString
*in_str
)
1044 int c
, index
, modifier
;
1059 if (*str
== 'c' || *str
== 'n' ||
1060 *str
== 'b' || *str
== 'w' || *str
== 'h' || *str
== 'k' ||
1062 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
1063 and make literal operands not be decorated with '$'. */
1066 index
= find_constraint(operands
, nb_operands
, str
, &str
);
1068 tcc_error("invalid operand reference after %%");
1069 op
= &operands
[index
];
1073 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& op
->is_memory
)
1076 subst_asm_operand(out_str
, &sv
, modifier
);
1079 cstr_ccat(out_str
, c
);
1087 static void parse_asm_operands(ASMOperand
*operands
, int *nb_operands_ptr
,
1094 nb_operands
= *nb_operands_ptr
;
1097 if (nb_operands
>= MAX_ASM_OPERANDS
)
1098 tcc_error("too many asm operands");
1099 op
= &operands
[nb_operands
++];
1103 if (tok
< TOK_IDENT
)
1104 expect("identifier");
1109 parse_mult_str(&astr
, "string constant");
1110 op
->constraint
= tcc_malloc(astr
.size
);
1111 strcpy(op
->constraint
, astr
.data
);
1116 if (!(vtop
->type
.t
& VT_ARRAY
))
1119 /* we want to avoid LLOCAL case, except when the 'm'
1120 constraint is used. Note that it may come from
1121 register storage, so we need to convert (reg)
1123 if ((vtop
->r
& VT_LVAL
) &&
1124 ((vtop
->r
& VT_VALMASK
) == VT_LLOCAL
||
1125 (vtop
->r
& VT_VALMASK
) < VT_CONST
) &&
1126 !strchr(op
->constraint
, 'm')) {
1138 *nb_operands_ptr
= nb_operands
;
1142 /* parse the GCC asm() instruction */
1143 ST_FUNC
void asm_instr(void)
1145 CString astr
, astr1
;
1146 ASMOperand operands
[MAX_ASM_OPERANDS
];
1147 int nb_outputs
, nb_operands
, i
, must_subst
, out_reg
;
1148 uint8_t clobber_regs
[NB_ASM_REGS
];
1151 /* since we always generate the asm() instruction, we can ignore
1153 if (tok
== TOK_VOLATILE1
|| tok
== TOK_VOLATILE2
|| tok
== TOK_VOLATILE3
) {
1156 parse_asm_str(&astr
);
1160 memset(clobber_regs
, 0, sizeof(clobber_regs
));
1165 parse_asm_operands(operands
, &nb_operands
, 1);
1166 nb_outputs
= nb_operands
;
1171 parse_asm_operands(operands
, &nb_operands
, 0);
1174 /* XXX: handle registers */
1178 expect("string constant");
1179 asm_clobber(clobber_regs
, tokc
.str
.data
);
1192 /* NOTE: we do not eat the ';' so that we can restore the current
1193 token after the assembler parsing */
1197 /* save all values in the memory */
1200 /* compute constraints */
1201 asm_compute_constraints(operands
, nb_operands
, nb_outputs
,
1202 clobber_regs
, &out_reg
);
1204 /* substitute the operands in the asm string. No substitution is
1205 done if no operands (GCC behaviour) */
1207 printf("asm: \"%s\"\n", (char *)astr
.data
);
1210 subst_asm_operands(operands
, nb_operands
, &astr1
, &astr
);
1216 printf("subst_asm: \"%s\"\n", (char *)astr1
.data
);
1219 /* generate loads */
1220 asm_gen_code(operands
, nb_operands
, nb_outputs
, 0,
1221 clobber_regs
, out_reg
);
1223 /* We don't allow switching section within inline asm to
1224 bleed out to surrounding code. */
1225 sec
= cur_text_section
;
1226 /* assemble the string with tcc internal assembler */
1227 tcc_assemble_inline(tcc_state
, astr1
.data
, astr1
.size
- 1, 0);
1228 if (sec
!= cur_text_section
) {
1229 tcc_warning("inline asm tries to change current section");
1230 use_section1(tcc_state
, sec
);
1233 /* restore the current C token */
1236 /* store the output values if needed */
1237 asm_gen_code(operands
, nb_operands
, nb_outputs
, 1,
1238 clobber_regs
, out_reg
);
1240 /* free everything */
1241 for(i
=0;i
<nb_operands
;i
++) {
1244 tcc_free(op
->constraint
);
1250 ST_FUNC
void asm_global_instr(void)
1253 int saved_nocode_wanted
= nocode_wanted
;
1255 /* Global asm blocks are always emitted. */
1258 parse_asm_str(&astr
);
1260 /* NOTE: we do not eat the ';' so that we can restore the current
1261 token after the assembler parsing */
1266 printf("asm_global: \"%s\"\n", (char *)astr
.data
);
1268 cur_text_section
= text_section
;
1269 ind
= cur_text_section
->data_offset
;
1271 /* assemble the string with tcc internal assembler */
1272 tcc_assemble_inline(tcc_state
, astr
.data
, astr
.size
- 1, 1);
1274 cur_text_section
->data_offset
= ind
;
1276 /* restore the current C token */
1280 nocode_wanted
= saved_nocode_wanted
;
1282 #endif /* CONFIG_TCC_ASM */