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 Sym
*sym
= global_identifier_push(v
, VT_ASM
| VT_EXTERN
| VT_STATIC
, 0);
52 sym
->r
= VT_CONST
| VT_SYM
;
56 /* Return a symbol we can use inside the assembler, having name NAME.
57 Symbols from asm and C source share a namespace. If we generate
58 an asm symbol it's also a (file-global) C symbol, but it's
59 either not accessible by name (like "L.123"), or its type information
60 is such that it's not usable without a proper C declaration.
62 Sometimes we need symbols accessible by name from asm, which
63 are anonymous in C, in this case CSYM can be used to transfer
64 all information from that symbol to the (possibly newly created)
66 ST_FUNC Sym
* get_asm_sym(int name
, Sym
*csym
)
68 Sym
*sym
= asm_label_find(name
);
70 sym
= asm_label_push(name
);
77 static Sym
* asm_section_sym(TCCState
*s1
, Section
*sec
)
80 int label
= tok_alloc(buf
,
81 snprintf(buf
, sizeof buf
, "L.%s", sec
->name
)
83 Sym
*sym
= asm_label_find(label
);
84 return sym
? sym
: asm_new_label1(s1
, label
, 1, sec
->sh_num
, 0);
87 /* We do not use the C expression parser to handle symbols. Maybe the
88 C expression parser could be tweaked to do so. */
90 static void asm_expr_unary(TCCState
*s1
, ExprValue
*pe
)
100 n
= strtoull(p
, (char **)&p
, 0);
101 if (*p
== 'b' || *p
== 'f') {
102 /* backward or forward label */
103 label
= asm_get_local_label_name(s1
, n
);
104 sym
= asm_label_find(label
);
106 /* backward : find the last corresponding defined label */
107 if (sym
&& (!sym
->c
|| elfsym(sym
)->st_shndx
== SHN_UNDEF
))
110 tcc_error("local label '%d' not found backward", n
);
113 if (!sym
|| (sym
->c
&& elfsym(sym
)->st_shndx
!= SHN_UNDEF
)) {
114 /* if the last label is defined, then define a new one */
115 sym
= asm_label_push(label
);
121 } else if (*p
== '\0') {
126 tcc_error("invalid number syntax");
132 asm_expr_unary(s1
, pe
);
138 asm_expr_unary(s1
, pe
);
140 tcc_error("invalid operation with label");
160 pe
->sym
= asm_section_sym(s1
, cur_text_section
);
165 if (tok
>= TOK_IDENT
) {
167 /* label case : if the label was not found, add one */
168 sym
= get_asm_sym(tok
, NULL
);
170 if (esym
&& esym
->st_shndx
== SHN_ABS
) {
171 /* if absolute symbol, no need to put a symbol value */
172 pe
->v
= esym
->st_value
;
182 tcc_error("bad expression syntax [%s]", get_tok_str(tok
, &tokc
));
188 static void asm_expr_prod(TCCState
*s1
, ExprValue
*pe
)
193 asm_expr_unary(s1
, pe
);
196 if (op
!= '*' && op
!= '/' && op
!= '%' &&
197 op
!= TOK_SHL
&& op
!= TOK_SAR
)
200 asm_expr_unary(s1
, &e2
);
201 if (pe
->sym
|| e2
.sym
)
202 tcc_error("invalid operation with label");
210 tcc_error("division by zero");
230 static void asm_expr_logic(TCCState
*s1
, ExprValue
*pe
)
235 asm_expr_prod(s1
, pe
);
238 if (op
!= '&' && op
!= '|' && op
!= '^')
241 asm_expr_prod(s1
, &e2
);
242 if (pe
->sym
|| e2
.sym
)
243 tcc_error("invalid operation with label");
259 static inline void asm_expr_sum(TCCState
*s1
, ExprValue
*pe
)
264 asm_expr_logic(s1
, pe
);
267 if (op
!= '+' && op
!= '-')
270 asm_expr_logic(s1
, &e2
);
272 if (pe
->sym
!= NULL
&& e2
.sym
!= NULL
)
273 goto cannot_relocate
;
275 if (pe
->sym
== NULL
&& e2
.sym
!= NULL
)
279 /* NOTE: we are less powerful than gas in that case
280 because we store only one symbol in the expression */
283 } else if (pe
->sym
== e2
.sym
) {
285 pe
->sym
= NULL
; /* same symbols can be subtracted to NULL */
287 ElfSym
*esym1
, *esym2
;
288 esym1
= elfsym(pe
->sym
);
289 esym2
= elfsym(e2
.sym
);
290 if (esym1
&& esym1
->st_shndx
== esym2
->st_shndx
291 && esym1
->st_shndx
!= SHN_UNDEF
) {
292 /* we also accept defined symbols in the same section */
293 pe
->v
+= esym1
->st_value
- esym2
->st_value
;
295 } else if (esym2
->st_shndx
== cur_text_section
->sh_num
) {
296 /* When subtracting a defined symbol in current section
297 this actually makes the value PC-relative. */
298 pe
->v
-= esym2
->st_value
- ind
- 4;
303 tcc_error("invalid operation with label");
310 static inline void asm_expr_cmp(TCCState
*s1
, ExprValue
*pe
)
315 asm_expr_sum(s1
, pe
);
318 if (op
!= TOK_EQ
&& op
!= TOK_NE
319 && (op
> TOK_GT
|| op
< TOK_ULE
))
322 asm_expr_sum(s1
, &e2
);
323 if (pe
->sym
|| e2
.sym
)
324 tcc_error("invalid operation with label");
327 pe
->v
= pe
->v
== e2
.v
;
330 pe
->v
= pe
->v
!= e2
.v
;
333 pe
->v
= (int64_t)pe
->v
< (int64_t)e2
.v
;
336 pe
->v
= (int64_t)pe
->v
>= (int64_t)e2
.v
;
339 pe
->v
= (int64_t)pe
->v
<= (int64_t)e2
.v
;
342 pe
->v
= (int64_t)pe
->v
> (int64_t)e2
.v
;
347 /* GAS compare results are -1/0 not 1/0. */
348 pe
->v
= -(int64_t)pe
->v
;
352 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
)
354 asm_expr_cmp(s1
, pe
);
357 ST_FUNC
int asm_int_expr(TCCState
*s1
)
366 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
,
367 int sh_num
, int value
)
372 sym
= asm_label_find(label
);
375 /* A VT_EXTERN symbol, even if it has a section is considered
376 overridable. This is how we "define" .set targets. Real
377 definitions won't have VT_EXTERN set. */
378 if (esym
&& esym
->st_shndx
!= SHN_UNDEF
) {
379 /* the label is already defined */
381 && (is_local
== 1 || (sym
->type
.t
& VT_EXTERN
)))
383 if (!(sym
->type
.t
& VT_EXTERN
))
384 tcc_error("assembler label '%s' already defined",
385 get_tok_str(label
, NULL
));
389 sym
= asm_label_push(label
);
392 put_extern_sym2(sym
, SHN_UNDEF
, 0, 0, 0);
394 esym
->st_shndx
= sh_num
;
395 esym
->st_value
= value
;
397 sym
->type
.t
&= ~VT_EXTERN
;
401 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
)
403 return asm_new_label1(s1
, label
, is_local
, cur_text_section
->sh_num
, ind
);
406 /* Set the value of LABEL to that of some expression (possibly
407 involving other symbols). LABEL can be overwritten later still. */
408 static Sym
* set_symbol(TCCState
*s1
, int label
)
417 esym
= elfsym(e
.sym
);
420 sym
= asm_new_label1(s1
, label
, 2, esym
? esym
->st_shndx
: SHN_ABS
, n
);
421 elfsym(sym
)->st_other
|= ST_ASM_SET
;
425 static void use_section1(TCCState
*s1
, Section
*sec
)
427 cur_text_section
->data_offset
= ind
;
428 cur_text_section
= sec
;
429 ind
= cur_text_section
->data_offset
;
432 static void use_section(TCCState
*s1
, const char *name
)
435 sec
= find_section(s1
, name
);
436 use_section1(s1
, sec
);
439 static void push_section(TCCState
*s1
, const char *name
)
441 Section
*sec
= find_section(s1
, name
);
442 sec
->prev
= cur_text_section
;
443 use_section1(s1
, sec
);
446 static void pop_section(TCCState
*s1
)
448 Section
*prev
= cur_text_section
->prev
;
450 tcc_error(".popsection without .pushsection");
451 cur_text_section
->prev
= NULL
;
452 use_section1(s1
, prev
);
455 static void asm_parse_directive(TCCState
*s1
, int global
)
457 int n
, offset
, v
, size
, tok1
;
461 /* assembler directive */
462 sec
= cur_text_section
;
464 case TOK_ASMDIR_align
:
465 case TOK_ASMDIR_balign
:
466 case TOK_ASMDIR_p2align
:
467 case TOK_ASMDIR_skip
:
468 case TOK_ASMDIR_space
:
471 n
= asm_int_expr(s1
);
472 if (tok1
== TOK_ASMDIR_p2align
)
475 tcc_error("invalid p2align, must be between 0 and 30");
477 tok1
= TOK_ASMDIR_align
;
479 if (tok1
== TOK_ASMDIR_align
|| tok1
== TOK_ASMDIR_balign
) {
480 if (n
< 0 || (n
& (n
-1)) != 0)
481 tcc_error("alignment must be a positive power of two");
482 offset
= (ind
+ n
- 1) & -n
;
484 /* the section must have a compatible alignment */
485 if (sec
->sh_addralign
< n
)
486 sec
->sh_addralign
= n
;
495 v
= asm_int_expr(s1
);
498 if (sec
->sh_type
!= SHT_NOBITS
) {
499 sec
->data_offset
= ind
;
500 ptr
= section_ptr_add(sec
, size
);
501 memset(ptr
, v
, size
);
505 case TOK_ASMDIR_quad
:
506 #ifdef TCC_TARGET_X86_64
516 if (tok
!= TOK_PPNUM
) {
518 tcc_error("64 bit constant");
520 vl
= strtoll(p
, (char **)&p
, 0);
524 if (sec
->sh_type
!= SHT_NOBITS
) {
525 /* XXX: endianness */
537 case TOK_ASMDIR_byte
:
540 case TOK_ASMDIR_word
:
541 case TOK_ASMDIR_short
:
544 case TOK_ASMDIR_long
:
552 if (sec
->sh_type
!= SHT_NOBITS
) {
555 #ifdef TCC_TARGET_X86_64
556 } else if (size
== 8) {
575 case TOK_ASMDIR_fill
:
577 int repeat
, size
, val
, i
, j
;
578 uint8_t repeat_buf
[8];
580 repeat
= asm_int_expr(s1
);
582 tcc_error("repeat < 0; .fill ignored");
589 size
= asm_int_expr(s1
);
591 tcc_error("size < 0; .fill ignored");
598 val
= asm_int_expr(s1
);
601 /* XXX: endianness */
603 repeat_buf
[1] = val
>> 8;
604 repeat_buf
[2] = val
>> 16;
605 repeat_buf
[3] = val
>> 24;
610 for(i
= 0; i
< repeat
; i
++) {
611 for(j
= 0; j
< size
; j
++) {
617 case TOK_ASMDIR_rept
:
620 TokenString
*init_str
;
622 repeat
= asm_int_expr(s1
);
623 init_str
= tok_str_alloc();
624 while (next(), tok
!= TOK_ASMDIR_endr
) {
626 tcc_error("we at end of file, .endr not found");
627 tok_str_add_tok(init_str
);
629 tok_str_add(init_str
, -1);
630 tok_str_add(init_str
, 0);
631 begin_macro(init_str
, 1);
632 while (repeat
-- > 0) {
633 tcc_assemble_internal(s1
, (parse_flags
& PARSE_FLAG_PREPROCESS
),
635 macro_ptr
= init_str
->str
;
649 esym
= elfsym(e
.sym
);
651 if (esym
->st_shndx
!= cur_text_section
->sh_num
)
652 expect("constant or same-section symbol");
656 tcc_error("attempt to .org backwards");
666 /* Also accept '.set stuff', but don't do anything with this.
667 It's used in GAS to set various features like '.set mips16'. */
669 set_symbol(s1
, tok1
);
671 case TOK_ASMDIR_globl
:
672 case TOK_ASMDIR_global
:
673 case TOK_ASMDIR_weak
:
674 case TOK_ASMDIR_hidden
:
679 sym
= get_asm_sym(tok
, NULL
);
680 if (tok1
!= TOK_ASMDIR_hidden
)
681 sym
->type
.t
&= ~VT_STATIC
;
682 if (tok1
== TOK_ASMDIR_weak
)
684 else if (tok1
== TOK_ASMDIR_hidden
)
685 sym
->a
.visibility
= STV_HIDDEN
;
688 } while (tok
== ',');
690 case TOK_ASMDIR_string
:
691 case TOK_ASMDIR_ascii
:
692 case TOK_ASMDIR_asciz
:
701 expect("string constant");
703 size
= tokc
.str
.size
;
704 if (t
== TOK_ASMDIR_ascii
&& size
> 0)
706 for(i
= 0; i
< size
; i
++)
711 } else if (tok
!= TOK_STR
) {
717 case TOK_ASMDIR_text
:
718 case TOK_ASMDIR_data
:
725 if (tok
!= ';' && tok
!= TOK_LINEFEED
) {
726 n
= asm_int_expr(s1
);
730 sprintf(sname
, "%s%d", get_tok_str(tok1
, NULL
), n
);
732 sprintf(sname
, "%s", get_tok_str(tok1
, NULL
));
733 use_section(s1
, sname
);
736 case TOK_ASMDIR_file
:
744 pstrcat(filename
, sizeof(filename
), tokc
.str
.data
);
746 pstrcat(filename
, sizeof(filename
), get_tok_str(tok
, NULL
));
748 if (s1
->warn_unsupported
)
749 tcc_warning("ignoring .file %s", filename
);
754 case TOK_ASMDIR_ident
:
762 pstrcat(ident
, sizeof(ident
), tokc
.str
.data
);
764 pstrcat(ident
, sizeof(ident
), get_tok_str(tok
, NULL
));
766 if (s1
->warn_unsupported
)
767 tcc_warning("ignoring .ident %s", ident
);
772 case TOK_ASMDIR_size
:
777 sym
= asm_label_find(tok
);
779 tcc_error("label not found: %s", get_tok_str(tok
, NULL
));
782 /* XXX .size name,label2-label1 */
783 if (s1
->warn_unsupported
)
784 tcc_warning("ignoring .size %s,*", get_tok_str(tok
, NULL
));
788 while (tok
!= TOK_LINEFEED
&& tok
!= ';' && tok
!= CH_EOF
) {
793 case TOK_ASMDIR_type
:
799 sym
= get_asm_sym(tok
, NULL
);
802 if (tok
== TOK_STR
) {
803 newtype
= tokc
.str
.data
;
805 if (tok
== '@' || tok
== '%')
807 newtype
= get_tok_str(tok
, NULL
);
810 if (!strcmp(newtype
, "function") || !strcmp(newtype
, "STT_FUNC")) {
811 sym
->type
.t
= (sym
->type
.t
& ~VT_BTYPE
) | VT_FUNC
;
813 else if (s1
->warn_unsupported
)
814 tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
815 get_tok_str(sym
->v
, NULL
), sym
->type
.t
, newtype
);
820 case TOK_ASMDIR_pushsection
:
821 case TOK_ASMDIR_section
:
824 int old_nb_section
= s1
->nb_sections
;
827 /* XXX: support more options */
830 while (tok
!= ';' && tok
!= TOK_LINEFEED
&& tok
!= ',') {
832 pstrcat(sname
, sizeof(sname
), tokc
.str
.data
);
834 pstrcat(sname
, sizeof(sname
), get_tok_str(tok
, NULL
));
838 /* skip section options */
841 expect("string constant");
845 if (tok
== '@' || tok
== '%')
850 last_text_section
= cur_text_section
;
851 if (tok1
== TOK_ASMDIR_section
)
852 use_section(s1
, sname
);
854 push_section(s1
, sname
);
855 /* If we just allocated a new section reset its alignment to
856 1. new_section normally acts for GCC compatibility and
857 sets alignment to PTR_SIZE. The assembler behaves different. */
858 if (old_nb_section
!= s1
->nb_sections
)
859 cur_text_section
->sh_addralign
= 1;
862 case TOK_ASMDIR_previous
:
866 if (!last_text_section
)
867 tcc_error("no previous section referenced");
868 sec
= cur_text_section
;
869 use_section1(s1
, last_text_section
);
870 last_text_section
= sec
;
873 case TOK_ASMDIR_popsection
:
877 #ifdef TCC_TARGET_I386
878 case TOK_ASMDIR_code16
:
884 case TOK_ASMDIR_code32
:
891 #ifdef TCC_TARGET_X86_64
892 /* added for compatibility with GAS */
893 case TOK_ASMDIR_code64
:
898 tcc_error("unknown assembler directive '.%s'", get_tok_str(tok
, NULL
));
904 /* assemble a file */
905 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
)
908 int saved_parse_flags
= parse_flags
;
910 parse_flags
= PARSE_FLAG_ASM_FILE
| PARSE_FLAG_TOK_STR
;
912 parse_flags
|= PARSE_FLAG_PREPROCESS
;
917 /* generate line number info */
918 if (global
&& s1
->do_debug
)
920 parse_flags
|= PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
923 /* horrible gas comment */
924 while (tok
!= TOK_LINEFEED
)
926 } else if (tok
>= TOK_ASMDIR_FIRST
&& tok
<= TOK_ASMDIR_LAST
) {
927 asm_parse_directive(s1
, global
);
928 } else if (tok
== TOK_PPNUM
) {
932 n
= strtoul(p
, (char **)&p
, 10);
935 /* new local label */
936 asm_new_label(s1
, asm_get_local_label_name(s1
, n
), 1);
940 } else if (tok
>= TOK_IDENT
) {
941 /* instruction or label */
946 asm_new_label(s1
, opcode
, 0);
949 } else if (tok
== '=') {
950 set_symbol(s1
, opcode
);
953 asm_opcode(s1
, opcode
);
957 if (tok
!= ';' && tok
!= TOK_LINEFEED
)
958 expect("end of line");
959 parse_flags
&= ~PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
962 parse_flags
= saved_parse_flags
;
966 /* Assemble the current file */
967 ST_FUNC
int tcc_assemble(TCCState
*s1
, int do_preprocess
)
971 /* default section is text */
972 cur_text_section
= text_section
;
973 ind
= cur_text_section
->data_offset
;
975 ret
= tcc_assemble_internal(s1
, do_preprocess
, 1);
976 cur_text_section
->data_offset
= ind
;
981 /********************************************************************/
982 /* GCC inline asm support */
984 /* assemble the string 'str' in the current C compilation unit without
985 C preprocessing. NOTE: str is modified by modifying the '\0' at the
987 static void tcc_assemble_inline(TCCState
*s1
, char *str
, int len
, int global
)
989 const int *saved_macro_ptr
= macro_ptr
;
990 int dotid
= set_idnum('.', IS_ID
);
992 tcc_open_bf(s1
, ":asm:", len
);
993 memcpy(file
->buffer
, str
, len
);
995 tcc_assemble_internal(s1
, 0, global
);
998 set_idnum('.', dotid
);
999 macro_ptr
= saved_macro_ptr
;
1002 /* find a constraint by its number or id (gcc 3 extended
1003 syntax). return -1 if not found. Return in *pp in char after the
1005 ST_FUNC
int find_constraint(ASMOperand
*operands
, int nb_operands
,
1006 const char *name
, const char **pp
)
1014 while (isnum(*name
)) {
1015 index
= (index
* 10) + (*name
) - '0';
1018 if ((unsigned)index
>= nb_operands
)
1020 } else if (*name
== '[') {
1022 p
= strchr(name
, ']');
1024 ts
= tok_alloc(name
, p
- name
);
1025 for(index
= 0; index
< nb_operands
; index
++) {
1026 if (operands
[index
].id
== ts
->tok
)
1043 static void subst_asm_operands(ASMOperand
*operands
, int nb_operands
,
1044 CString
*out_str
, CString
*in_str
)
1046 int c
, index
, modifier
;
1061 if (*str
== 'c' || *str
== 'n' ||
1062 *str
== 'b' || *str
== 'w' || *str
== 'h' || *str
== 'k' ||
1064 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
1065 and make literal operands not be decorated with '$'. */
1068 index
= find_constraint(operands
, nb_operands
, str
, &str
);
1070 tcc_error("invalid operand reference after %%");
1071 op
= &operands
[index
];
1075 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& op
->is_memory
)
1078 subst_asm_operand(out_str
, &sv
, modifier
);
1081 cstr_ccat(out_str
, c
);
1089 static void parse_asm_operands(ASMOperand
*operands
, int *nb_operands_ptr
,
1096 nb_operands
= *nb_operands_ptr
;
1099 if (nb_operands
>= MAX_ASM_OPERANDS
)
1100 tcc_error("too many asm operands");
1101 op
= &operands
[nb_operands
++];
1105 if (tok
< TOK_IDENT
)
1106 expect("identifier");
1111 parse_mult_str(&astr
, "string constant");
1112 op
->constraint
= tcc_malloc(astr
.size
);
1113 strcpy(op
->constraint
, astr
.data
);
1118 if (!(vtop
->type
.t
& VT_ARRAY
))
1121 /* we want to avoid LLOCAL case, except when the 'm'
1122 constraint is used. Note that it may come from
1123 register storage, so we need to convert (reg)
1125 if ((vtop
->r
& VT_LVAL
) &&
1126 ((vtop
->r
& VT_VALMASK
) == VT_LLOCAL
||
1127 (vtop
->r
& VT_VALMASK
) < VT_CONST
) &&
1128 !strchr(op
->constraint
, 'm')) {
1140 *nb_operands_ptr
= nb_operands
;
1144 /* parse the GCC asm() instruction */
1145 ST_FUNC
void asm_instr(void)
1147 CString astr
, astr1
;
1148 ASMOperand operands
[MAX_ASM_OPERANDS
];
1149 int nb_outputs
, nb_operands
, i
, must_subst
, out_reg
;
1150 uint8_t clobber_regs
[NB_ASM_REGS
];
1153 /* since we always generate the asm() instruction, we can ignore
1155 if (tok
== TOK_VOLATILE1
|| tok
== TOK_VOLATILE2
|| tok
== TOK_VOLATILE3
) {
1158 parse_asm_str(&astr
);
1162 memset(clobber_regs
, 0, sizeof(clobber_regs
));
1167 parse_asm_operands(operands
, &nb_operands
, 1);
1168 nb_outputs
= nb_operands
;
1173 parse_asm_operands(operands
, &nb_operands
, 0);
1176 /* XXX: handle registers */
1180 expect("string constant");
1181 asm_clobber(clobber_regs
, tokc
.str
.data
);
1194 /* NOTE: we do not eat the ';' so that we can restore the current
1195 token after the assembler parsing */
1199 /* save all values in the memory */
1202 /* compute constraints */
1203 asm_compute_constraints(operands
, nb_operands
, nb_outputs
,
1204 clobber_regs
, &out_reg
);
1206 /* substitute the operands in the asm string. No substitution is
1207 done if no operands (GCC behaviour) */
1209 printf("asm: \"%s\"\n", (char *)astr
.data
);
1212 subst_asm_operands(operands
, nb_operands
, &astr1
, &astr
);
1218 printf("subst_asm: \"%s\"\n", (char *)astr1
.data
);
1221 /* generate loads */
1222 asm_gen_code(operands
, nb_operands
, nb_outputs
, 0,
1223 clobber_regs
, out_reg
);
1225 /* assemble the string with tcc internal assembler */
1226 tcc_assemble_inline(tcc_state
, astr1
.data
, astr1
.size
- 1, 0);
1228 /* restore the current C token */
1231 /* store the output values if needed */
1232 asm_gen_code(operands
, nb_operands
, nb_outputs
, 1,
1233 clobber_regs
, out_reg
);
1235 /* free everything */
1236 for(i
=0;i
<nb_operands
;i
++) {
1239 tcc_free(op
->constraint
);
1245 ST_FUNC
void asm_global_instr(void)
1248 int saved_nocode_wanted
= nocode_wanted
;
1250 /* Global asm blocks are always emitted. */
1253 parse_asm_str(&astr
);
1255 /* NOTE: we do not eat the ';' so that we can restore the current
1256 token after the assembler parsing */
1261 printf("asm_global: \"%s\"\n", (char *)astr
.data
);
1263 cur_text_section
= text_section
;
1264 ind
= cur_text_section
->data_offset
;
1266 /* assemble the string with tcc internal assembler */
1267 tcc_assemble_inline(tcc_state
, astr
.data
, astr
.size
- 1, 1);
1269 cur_text_section
->data_offset
= ind
;
1271 /* restore the current C token */
1275 nocode_wanted
= saved_nocode_wanted
;
1277 #endif /* CONFIG_TCC_ASM */