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 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
);
35 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
);
36 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
, int sh_num
, int value
);
38 static Sym
*asm_label_find(int v
)
40 Sym
*sym
= sym_find(v
);
41 while (sym
&& sym
->sym_scope
)
46 static Sym
*asm_label_push(int v
)
48 /* We always add VT_EXTERN, for sym definition that's tentative
49 (for .set, removed for real defs), for mere references it's correct
51 return global_identifier_push(v
, VT_ASM
| VT_EXTERN
| VT_STATIC
, 0);
54 /* Return a symbol we can use inside the assembler, having name NAME.
55 Symbols from asm and C source share a namespace. If we generate
56 an asm symbol it's also a (file-global) C symbol, but it's
57 either not accessible by name (like "L.123"), or its type information
58 is such that it's not usable without a proper C declaration.
60 Sometimes we need symbols accessible by name from asm, which
61 are anonymous in C, in this case CSYM can be used to transfer
62 all information from that symbol to the (possibly newly created)
64 ST_FUNC Sym
* get_asm_sym(int name
, Sym
*csym
)
66 Sym
*sym
= asm_label_find(name
);
68 sym
= asm_label_push(name
);
75 static Sym
* asm_section_sym(TCCState
*s1
, Section
*sec
)
78 int label
= tok_alloc(buf
,
79 snprintf(buf
, sizeof buf
, "L.%s", sec
->name
)
81 Sym
*sym
= asm_label_find(label
);
82 return sym
? sym
: asm_new_label1(s1
, label
, 1, sec
->sh_num
, 0);
85 /* We do not use the C expression parser to handle symbols. Maybe the
86 C expression parser could be tweaked to do so. */
88 static void asm_expr_unary(TCCState
*s1
, ExprValue
*pe
)
98 n
= strtoull(p
, (char **)&p
, 0);
99 if (*p
== 'b' || *p
== 'f') {
100 /* backward or forward label */
101 label
= asm_get_local_label_name(s1
, n
);
102 sym
= asm_label_find(label
);
104 /* backward : find the last corresponding defined label */
105 if (sym
&& (!sym
->c
|| elfsym(sym
)->st_shndx
== SHN_UNDEF
))
108 tcc_error("local label '%d' not found backward", n
);
111 if (!sym
|| (sym
->c
&& elfsym(sym
)->st_shndx
!= SHN_UNDEF
)) {
112 /* if the last label is defined, then define a new one */
113 sym
= asm_label_push(label
);
119 } else if (*p
== '\0') {
124 tcc_error("invalid number syntax");
130 asm_expr_unary(s1
, pe
);
136 asm_expr_unary(s1
, pe
);
138 tcc_error("invalid operation with label");
158 pe
->sym
= asm_section_sym(s1
, cur_text_section
);
163 if (tok
>= TOK_IDENT
) {
165 /* label case : if the label was not found, add one */
166 sym
= get_asm_sym(tok
, NULL
);
168 if (esym
&& esym
->st_shndx
== SHN_ABS
) {
169 /* if absolute symbol, no need to put a symbol value */
170 pe
->v
= esym
->st_value
;
180 tcc_error("bad expression syntax [%s]", get_tok_str(tok
, &tokc
));
186 static void asm_expr_prod(TCCState
*s1
, ExprValue
*pe
)
191 asm_expr_unary(s1
, pe
);
194 if (op
!= '*' && op
!= '/' && op
!= '%' &&
195 op
!= TOK_SHL
&& op
!= TOK_SAR
)
198 asm_expr_unary(s1
, &e2
);
199 if (pe
->sym
|| e2
.sym
)
200 tcc_error("invalid operation with label");
208 tcc_error("division by zero");
228 static void asm_expr_logic(TCCState
*s1
, ExprValue
*pe
)
233 asm_expr_prod(s1
, pe
);
236 if (op
!= '&' && op
!= '|' && op
!= '^')
239 asm_expr_prod(s1
, &e2
);
240 if (pe
->sym
|| e2
.sym
)
241 tcc_error("invalid operation with label");
257 static inline void asm_expr_sum(TCCState
*s1
, ExprValue
*pe
)
262 asm_expr_logic(s1
, pe
);
265 if (op
!= '+' && op
!= '-')
268 asm_expr_logic(s1
, &e2
);
270 if (pe
->sym
!= NULL
&& e2
.sym
!= NULL
)
271 goto cannot_relocate
;
273 if (pe
->sym
== NULL
&& e2
.sym
!= NULL
)
277 /* NOTE: we are less powerful than gas in that case
278 because we store only one symbol in the expression */
281 } else if (pe
->sym
== e2
.sym
) {
283 pe
->sym
= NULL
; /* same symbols can be subtracted to NULL */
285 ElfSym
*esym1
, *esym2
;
286 esym1
= elfsym(pe
->sym
);
287 esym2
= elfsym(e2
.sym
);
288 if (esym1
&& esym1
->st_shndx
== esym2
->st_shndx
289 && esym1
->st_shndx
!= SHN_UNDEF
) {
290 /* we also accept defined symbols in the same section */
291 pe
->v
+= esym1
->st_value
- esym2
->st_value
;
293 } else if (esym2
->st_shndx
== cur_text_section
->sh_num
) {
294 /* When subtracting a defined symbol in current section
295 this actually makes the value PC-relative. */
296 pe
->v
-= esym2
->st_value
- ind
- 4;
301 tcc_error("invalid operation with label");
308 static inline void asm_expr_cmp(TCCState
*s1
, ExprValue
*pe
)
313 asm_expr_sum(s1
, pe
);
316 if (op
!= TOK_EQ
&& op
!= TOK_NE
317 && (op
> TOK_GT
|| op
< TOK_ULE
))
320 asm_expr_sum(s1
, &e2
);
321 if (pe
->sym
|| e2
.sym
)
322 tcc_error("invalid operation with label");
325 pe
->v
= pe
->v
== e2
.v
;
328 pe
->v
= pe
->v
!= e2
.v
;
331 pe
->v
= (int64_t)pe
->v
< (int64_t)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
;
345 /* GAS compare results are -1/0 not 1/0. */
346 pe
->v
= -(int64_t)pe
->v
;
350 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
)
352 asm_expr_cmp(s1
, pe
);
355 ST_FUNC
int asm_int_expr(TCCState
*s1
)
364 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
,
365 int sh_num
, int value
)
370 sym
= asm_label_find(label
);
373 /* A VT_EXTERN symbol, even if it has a section is considered
374 overridable. This is how we "define" .set targets. Real
375 definitions won't have VT_EXTERN set. */
376 if (esym
&& esym
->st_shndx
!= SHN_UNDEF
) {
377 /* the label is already defined */
379 && (is_local
== 1 || (sym
->type
.t
& VT_EXTERN
)))
381 if (!(sym
->type
.t
& VT_EXTERN
))
382 tcc_error("assembler label '%s' already defined",
383 get_tok_str(label
, NULL
));
387 sym
= asm_label_push(label
);
390 put_extern_sym2(sym
, SHN_UNDEF
, 0, 0, 0);
392 esym
->st_shndx
= sh_num
;
393 esym
->st_value
= value
;
395 sym
->type
.t
&= ~VT_EXTERN
;
399 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
)
401 return asm_new_label1(s1
, label
, is_local
, cur_text_section
->sh_num
, ind
);
404 /* Set the value of LABEL to that of some expression (possibly
405 involving other symbols). LABEL can be overwritten later still. */
406 static Sym
* set_symbol(TCCState
*s1
, int label
)
415 esym
= elfsym(e
.sym
);
418 sym
= asm_new_label1(s1
, label
, 2, esym
? esym
->st_shndx
: SHN_ABS
, n
);
419 elfsym(sym
)->st_other
|= ST_ASM_SET
;
423 static void use_section1(TCCState
*s1
, Section
*sec
)
425 cur_text_section
->data_offset
= ind
;
426 cur_text_section
= sec
;
427 ind
= cur_text_section
->data_offset
;
430 static void use_section(TCCState
*s1
, const char *name
)
433 sec
= find_section(s1
, name
);
434 use_section1(s1
, sec
);
437 static void push_section(TCCState
*s1
, const char *name
)
439 Section
*sec
= find_section(s1
, name
);
440 sec
->prev
= cur_text_section
;
441 use_section1(s1
, sec
);
444 static void pop_section(TCCState
*s1
)
446 Section
*prev
= cur_text_section
->prev
;
448 tcc_error(".popsection without .pushsection");
449 cur_text_section
->prev
= NULL
;
450 use_section1(s1
, prev
);
453 static void asm_parse_directive(TCCState
*s1
, int global
)
455 int n
, offset
, v
, size
, tok1
;
459 /* assembler directive */
460 sec
= cur_text_section
;
462 case TOK_ASMDIR_align
:
463 case TOK_ASMDIR_balign
:
464 case TOK_ASMDIR_p2align
:
465 case TOK_ASMDIR_skip
:
466 case TOK_ASMDIR_space
:
469 n
= asm_int_expr(s1
);
470 if (tok1
== TOK_ASMDIR_p2align
)
473 tcc_error("invalid p2align, must be between 0 and 30");
475 tok1
= TOK_ASMDIR_align
;
477 if (tok1
== TOK_ASMDIR_align
|| tok1
== TOK_ASMDIR_balign
) {
478 if (n
< 0 || (n
& (n
-1)) != 0)
479 tcc_error("alignment must be a positive power of two");
480 offset
= (ind
+ n
- 1) & -n
;
482 /* the section must have a compatible alignment */
483 if (sec
->sh_addralign
< n
)
484 sec
->sh_addralign
= n
;
493 v
= asm_int_expr(s1
);
496 if (sec
->sh_type
!= SHT_NOBITS
) {
497 sec
->data_offset
= ind
;
498 ptr
= section_ptr_add(sec
, size
);
499 memset(ptr
, v
, size
);
503 case TOK_ASMDIR_quad
:
504 #ifdef TCC_TARGET_X86_64
514 if (tok
!= TOK_PPNUM
) {
516 tcc_error("64 bit constant");
518 vl
= strtoll(p
, (char **)&p
, 0);
522 if (sec
->sh_type
!= SHT_NOBITS
) {
523 /* XXX: endianness */
535 case TOK_ASMDIR_byte
:
538 case TOK_ASMDIR_word
:
539 case TOK_ASMDIR_short
:
542 case TOK_ASMDIR_long
:
550 if (sec
->sh_type
!= SHT_NOBITS
) {
553 #ifdef TCC_TARGET_X86_64
554 } else if (size
== 8) {
573 case TOK_ASMDIR_fill
:
575 int repeat
, size
, val
, i
, j
;
576 uint8_t repeat_buf
[8];
578 repeat
= asm_int_expr(s1
);
580 tcc_error("repeat < 0; .fill ignored");
587 size
= asm_int_expr(s1
);
589 tcc_error("size < 0; .fill ignored");
596 val
= asm_int_expr(s1
);
599 /* XXX: endianness */
601 repeat_buf
[1] = val
>> 8;
602 repeat_buf
[2] = val
>> 16;
603 repeat_buf
[3] = val
>> 24;
608 for(i
= 0; i
< repeat
; i
++) {
609 for(j
= 0; j
< size
; j
++) {
615 case TOK_ASMDIR_rept
:
618 TokenString
*init_str
;
620 repeat
= asm_int_expr(s1
);
621 init_str
= tok_str_alloc();
622 while (next(), tok
!= TOK_ASMDIR_endr
) {
624 tcc_error("we at end of file, .endr not found");
625 tok_str_add_tok(init_str
);
627 tok_str_add(init_str
, -1);
628 tok_str_add(init_str
, 0);
629 begin_macro(init_str
, 1);
630 while (repeat
-- > 0) {
631 tcc_assemble_internal(s1
, (parse_flags
& PARSE_FLAG_PREPROCESS
),
633 macro_ptr
= init_str
->str
;
647 esym
= elfsym(e
.sym
);
649 if (esym
->st_shndx
!= cur_text_section
->sh_num
)
650 expect("constant or same-section symbol");
654 tcc_error("attempt to .org backwards");
664 /* Also accept '.set stuff', but don't do anything with this.
665 It's used in GAS to set various features like '.set mips16'. */
667 set_symbol(s1
, tok1
);
669 case TOK_ASMDIR_globl
:
670 case TOK_ASMDIR_global
:
671 case TOK_ASMDIR_weak
:
672 case TOK_ASMDIR_hidden
:
677 sym
= get_asm_sym(tok
, NULL
);
678 if (tok1
!= TOK_ASMDIR_hidden
)
679 sym
->type
.t
&= ~VT_STATIC
;
680 if (tok1
== TOK_ASMDIR_weak
)
682 else if (tok1
== TOK_ASMDIR_hidden
)
683 sym
->a
.visibility
= STV_HIDDEN
;
686 } while (tok
== ',');
688 case TOK_ASMDIR_string
:
689 case TOK_ASMDIR_ascii
:
690 case TOK_ASMDIR_asciz
:
699 expect("string constant");
701 size
= tokc
.str
.size
;
702 if (t
== TOK_ASMDIR_ascii
&& size
> 0)
704 for(i
= 0; i
< size
; i
++)
709 } else if (tok
!= TOK_STR
) {
715 case TOK_ASMDIR_text
:
716 case TOK_ASMDIR_data
:
723 if (tok
!= ';' && tok
!= TOK_LINEFEED
) {
724 n
= asm_int_expr(s1
);
728 sprintf(sname
, "%s%d", get_tok_str(tok1
, NULL
), n
);
730 sprintf(sname
, "%s", get_tok_str(tok1
, NULL
));
731 use_section(s1
, sname
);
734 case TOK_ASMDIR_file
:
742 pstrcat(filename
, sizeof(filename
), tokc
.str
.data
);
744 pstrcat(filename
, sizeof(filename
), get_tok_str(tok
, NULL
));
746 if (s1
->warn_unsupported
)
747 tcc_warning("ignoring .file %s", filename
);
752 case TOK_ASMDIR_ident
:
760 pstrcat(ident
, sizeof(ident
), tokc
.str
.data
);
762 pstrcat(ident
, sizeof(ident
), get_tok_str(tok
, NULL
));
764 if (s1
->warn_unsupported
)
765 tcc_warning("ignoring .ident %s", ident
);
770 case TOK_ASMDIR_size
:
775 sym
= asm_label_find(tok
);
777 tcc_error("label not found: %s", get_tok_str(tok
, NULL
));
780 /* XXX .size name,label2-label1 */
781 if (s1
->warn_unsupported
)
782 tcc_warning("ignoring .size %s,*", get_tok_str(tok
, NULL
));
786 while (tok
!= TOK_LINEFEED
&& tok
!= ';' && tok
!= CH_EOF
) {
791 case TOK_ASMDIR_type
:
797 sym
= get_asm_sym(tok
, NULL
);
800 if (tok
== TOK_STR
) {
801 newtype
= tokc
.str
.data
;
803 if (tok
== '@' || tok
== '%')
805 newtype
= get_tok_str(tok
, NULL
);
808 if (!strcmp(newtype
, "function") || !strcmp(newtype
, "STT_FUNC")) {
809 sym
->type
.t
= (sym
->type
.t
& ~VT_BTYPE
) | VT_FUNC
;
811 else if (s1
->warn_unsupported
)
812 tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
813 get_tok_str(sym
->v
, NULL
), sym
->type
.t
, newtype
);
818 case TOK_ASMDIR_pushsection
:
819 case TOK_ASMDIR_section
:
822 int old_nb_section
= s1
->nb_sections
;
825 /* XXX: support more options */
828 while (tok
!= ';' && tok
!= TOK_LINEFEED
&& tok
!= ',') {
830 pstrcat(sname
, sizeof(sname
), tokc
.str
.data
);
832 pstrcat(sname
, sizeof(sname
), get_tok_str(tok
, NULL
));
836 /* skip section options */
839 expect("string constant");
843 if (tok
== '@' || tok
== '%')
848 last_text_section
= cur_text_section
;
849 if (tok1
== TOK_ASMDIR_section
)
850 use_section(s1
, sname
);
852 push_section(s1
, sname
);
853 /* If we just allocated a new section reset its alignment to
854 1. new_section normally acts for GCC compatibility and
855 sets alignment to PTR_SIZE. The assembler behaves different. */
856 if (old_nb_section
!= s1
->nb_sections
)
857 cur_text_section
->sh_addralign
= 1;
860 case TOK_ASMDIR_previous
:
864 if (!last_text_section
)
865 tcc_error("no previous section referenced");
866 sec
= cur_text_section
;
867 use_section1(s1
, last_text_section
);
868 last_text_section
= sec
;
871 case TOK_ASMDIR_popsection
:
875 #ifdef TCC_TARGET_I386
876 case TOK_ASMDIR_code16
:
882 case TOK_ASMDIR_code32
:
889 #ifdef TCC_TARGET_X86_64
890 /* added for compatibility with GAS */
891 case TOK_ASMDIR_code64
:
896 tcc_error("unknown assembler directive '.%s'", get_tok_str(tok
, NULL
));
902 /* assemble a file */
903 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
)
906 int saved_parse_flags
= parse_flags
;
908 parse_flags
= PARSE_FLAG_ASM_FILE
| PARSE_FLAG_TOK_STR
;
910 parse_flags
|= PARSE_FLAG_PREPROCESS
;
915 /* generate line number info */
916 if (global
&& s1
->do_debug
)
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
];
1152 /* since we always generate the asm() instruction, we can ignore
1154 if (tok
== TOK_VOLATILE1
|| tok
== TOK_VOLATILE2
|| tok
== TOK_VOLATILE3
) {
1157 parse_asm_str(&astr
);
1161 memset(clobber_regs
, 0, sizeof(clobber_regs
));
1166 parse_asm_operands(operands
, &nb_operands
, 1);
1167 nb_outputs
= nb_operands
;
1172 parse_asm_operands(operands
, &nb_operands
, 0);
1175 /* XXX: handle registers */
1179 expect("string constant");
1180 asm_clobber(clobber_regs
, tokc
.str
.data
);
1193 /* NOTE: we do not eat the ';' so that we can restore the current
1194 token after the assembler parsing */
1198 /* save all values in the memory */
1201 /* compute constraints */
1202 asm_compute_constraints(operands
, nb_operands
, nb_outputs
,
1203 clobber_regs
, &out_reg
);
1205 /* substitute the operands in the asm string. No substitution is
1206 done if no operands (GCC behaviour) */
1208 printf("asm: \"%s\"\n", (char *)astr
.data
);
1211 subst_asm_operands(operands
, nb_operands
, &astr1
, &astr
);
1217 printf("subst_asm: \"%s\"\n", (char *)astr1
.data
);
1220 /* generate loads */
1221 asm_gen_code(operands
, nb_operands
, nb_outputs
, 0,
1222 clobber_regs
, out_reg
);
1224 /* We don't allow switching section within inline asm to
1225 bleed out to surrounding code. */
1226 sec
= cur_text_section
;
1227 /* assemble the string with tcc internal assembler */
1228 tcc_assemble_inline(tcc_state
, astr1
.data
, astr1
.size
- 1, 0);
1229 if (sec
!= cur_text_section
) {
1230 tcc_warning("inline asm tries to change current section");
1231 use_section1(tcc_state
, sec
);
1234 /* restore the current C token */
1237 /* store the output values if needed */
1238 asm_gen_code(operands
, nb_operands
, nb_outputs
, 1,
1239 clobber_regs
, out_reg
);
1241 /* free everything */
1242 for(i
=0;i
<nb_operands
;i
++) {
1245 tcc_free(op
->constraint
);
1251 ST_FUNC
void asm_global_instr(void)
1254 int saved_nocode_wanted
= nocode_wanted
;
1256 /* Global asm blocks are always emitted. */
1259 parse_asm_str(&astr
);
1261 /* NOTE: we do not eat the ';' so that we can restore the current
1262 token after the assembler parsing */
1267 printf("asm_global: \"%s\"\n", (char *)astr
.data
);
1269 cur_text_section
= text_section
;
1270 ind
= cur_text_section
->data_offset
;
1272 /* assemble the string with tcc internal assembler */
1273 tcc_assemble_inline(tcc_state
, astr
.data
, astr
.size
- 1, 1);
1275 cur_text_section
->data_offset
= ind
;
1277 /* restore the current C token */
1281 nocode_wanted
= saved_nocode_wanted
;
1283 #endif /* CONFIG_TCC_ASM */