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 */
28 static int asm_get_prefix_name(TCCState
*s1
, const char *prefix
, unsigned int n
)
31 snprintf(buf
, sizeof(buf
), "%s%u", prefix
, n
);
32 return tok_alloc_const(buf
);
35 ST_FUNC
int asm_get_local_label_name(TCCState
*s1
, unsigned int n
)
37 return asm_get_prefix_name(s1
, "L..", n
);
40 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
);
41 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
);
42 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
, int sh_num
, int value
);
44 /* If a C name has an _ prepended then only asm labels that start
45 with _ are representable in C, by removing the first _. ASM names
46 without _ at the beginning don't correspond to C names, but we use
47 the global C symbol table to track ASM names as well, so we need to
48 transform those into ones that don't conflict with a C name,
49 so prepend a '.' for them, but force the ELF asm name to be set. */
50 static int asm2cname(int v
, int *addeddot
)
54 if (!tcc_state
->leading_underscore
)
56 name
= get_tok_str(v
, NULL
);
60 v
= tok_alloc_const(name
+ 1);
61 } else if (!strchr(name
, '.')) {
63 snprintf(newname
, sizeof newname
, ".%s", name
);
64 v
= tok_alloc_const(newname
);
70 static Sym
*asm_label_find(int v
)
74 v
= asm2cname(v
, &addeddot
);
76 while (sym
&& sym
->sym_scope
&& !(sym
->type
.t
& VT_STATIC
))
81 static Sym
*asm_label_push(int v
)
83 int addeddot
, v2
= asm2cname(v
, &addeddot
);
84 /* We always add VT_EXTERN, for sym definition that's tentative
85 (for .set, removed for real defs), for mere references it's correct
87 Sym
*sym
= global_identifier_push(v2
, VT_ASM
| VT_EXTERN
| VT_STATIC
, 0);
93 /* Return a symbol we can use inside the assembler, having name NAME.
94 Symbols from asm and C source share a namespace. If we generate
95 an asm symbol it's also a (file-global) C symbol, but it's
96 either not accessible by name (like "L.123"), or its type information
97 is such that it's not usable without a proper C declaration.
99 Sometimes we need symbols accessible by name from asm, which
100 are anonymous in C, in this case CSYM can be used to transfer
101 all information from that symbol to the (possibly newly created)
103 ST_FUNC Sym
* get_asm_sym(int name
, Sym
*csym
)
105 Sym
*sym
= asm_label_find(name
);
107 sym
= asm_label_push(name
);
114 static Sym
* asm_section_sym(TCCState
*s1
, Section
*sec
)
116 char buf
[100]; int label
; Sym
*sym
;
117 snprintf(buf
, sizeof buf
, "L.%s", sec
->name
);
118 label
= tok_alloc_const(buf
);
119 sym
= asm_label_find(label
);
120 return sym
? sym
: asm_new_label1(s1
, label
, 1, sec
->sh_num
, 0);
123 /* We do not use the C expression parser to handle symbols. Maybe the
124 C expression parser could be tweaked to do so. */
126 static void asm_expr_unary(TCCState
*s1
, ExprValue
*pe
)
136 n
= strtoull(p
, (char **)&p
, 0);
137 if (*p
== 'b' || *p
== 'f') {
138 /* backward or forward label */
139 label
= asm_get_local_label_name(s1
, n
);
140 sym
= asm_label_find(label
);
142 /* backward : find the last corresponding defined label */
143 if (sym
&& (!sym
->c
|| elfsym(sym
)->st_shndx
== SHN_UNDEF
))
146 tcc_error("local label '%d' not found backward", (int)n
);
149 if (!sym
|| (sym
->c
&& elfsym(sym
)->st_shndx
!= SHN_UNDEF
)) {
150 /* if the last label is defined, then define a new one */
151 sym
= asm_label_push(label
);
157 } else if (*p
== '\0') {
162 tcc_error("invalid number syntax");
168 asm_expr_unary(s1
, pe
);
174 asm_expr_unary(s1
, pe
);
176 tcc_error("invalid operation with label");
196 pe
->sym
= asm_section_sym(s1
, cur_text_section
);
201 if (tok
>= TOK_IDENT
) {
203 /* label case : if the label was not found, add one */
204 sym
= get_asm_sym(tok
, NULL
);
206 if (esym
&& esym
->st_shndx
== SHN_ABS
) {
207 /* if absolute symbol, no need to put a symbol value */
208 pe
->v
= esym
->st_value
;
218 tcc_error("bad expression syntax [%s]", get_tok_str(tok
, &tokc
));
224 static void asm_expr_prod(TCCState
*s1
, ExprValue
*pe
)
229 asm_expr_unary(s1
, pe
);
232 if (op
!= '*' && op
!= '/' && op
!= '%' &&
233 op
!= TOK_SHL
&& op
!= TOK_SAR
)
236 asm_expr_unary(s1
, &e2
);
237 if (pe
->sym
|| e2
.sym
)
238 tcc_error("invalid operation with label");
246 tcc_error("division by zero");
266 static void asm_expr_logic(TCCState
*s1
, ExprValue
*pe
)
271 asm_expr_prod(s1
, pe
);
274 if (op
!= '&' && op
!= '|' && op
!= '^')
277 asm_expr_prod(s1
, &e2
);
278 if (pe
->sym
|| e2
.sym
)
279 tcc_error("invalid operation with label");
295 static inline void asm_expr_sum(TCCState
*s1
, ExprValue
*pe
)
300 asm_expr_logic(s1
, pe
);
303 if (op
!= '+' && op
!= '-')
306 asm_expr_logic(s1
, &e2
);
308 if (pe
->sym
!= NULL
&& e2
.sym
!= NULL
)
309 goto cannot_relocate
;
311 if (pe
->sym
== NULL
&& e2
.sym
!= NULL
)
315 /* NOTE: we are less powerful than gas in that case
316 because we store only one symbol in the expression */
319 } else if (pe
->sym
== e2
.sym
) {
321 pe
->sym
= NULL
; /* same symbols can be subtracted to NULL */
323 ElfSym
*esym1
, *esym2
;
324 esym1
= elfsym(pe
->sym
);
325 esym2
= elfsym(e2
.sym
);
326 if (esym1
&& esym1
->st_shndx
== esym2
->st_shndx
327 && esym1
->st_shndx
!= SHN_UNDEF
) {
328 /* we also accept defined symbols in the same section */
329 pe
->v
+= esym1
->st_value
- esym2
->st_value
;
331 } else if (esym2
->st_shndx
== cur_text_section
->sh_num
) {
332 /* When subtracting a defined symbol in current section
333 this actually makes the value PC-relative. */
334 pe
->v
-= esym2
->st_value
- ind
- 4;
339 tcc_error("invalid operation with label");
346 static inline void asm_expr_cmp(TCCState
*s1
, ExprValue
*pe
)
351 asm_expr_sum(s1
, pe
);
354 if (op
!= TOK_EQ
&& op
!= TOK_NE
355 && (op
> TOK_GT
|| op
< TOK_ULE
))
358 asm_expr_sum(s1
, &e2
);
359 if (pe
->sym
|| e2
.sym
)
360 tcc_error("invalid operation with label");
363 pe
->v
= pe
->v
== e2
.v
;
366 pe
->v
= pe
->v
!= e2
.v
;
369 pe
->v
= (int64_t)pe
->v
< (int64_t)e2
.v
;
372 pe
->v
= (int64_t)pe
->v
>= (int64_t)e2
.v
;
375 pe
->v
= (int64_t)pe
->v
<= (int64_t)e2
.v
;
378 pe
->v
= (int64_t)pe
->v
> (int64_t)e2
.v
;
383 /* GAS compare results are -1/0 not 1/0. */
384 pe
->v
= -(int64_t)pe
->v
;
388 ST_FUNC
void asm_expr(TCCState
*s1
, ExprValue
*pe
)
390 asm_expr_cmp(s1
, pe
);
393 ST_FUNC
int asm_int_expr(TCCState
*s1
)
402 static Sym
* asm_new_label1(TCCState
*s1
, int label
, int is_local
,
403 int sh_num
, int value
)
408 sym
= asm_label_find(label
);
411 /* A VT_EXTERN symbol, even if it has a section is considered
412 overridable. This is how we "define" .set targets. Real
413 definitions won't have VT_EXTERN set. */
414 if (esym
&& esym
->st_shndx
!= SHN_UNDEF
) {
415 /* the label is already defined */
417 && (is_local
== 1 || (sym
->type
.t
& VT_EXTERN
)))
419 if (!(sym
->type
.t
& VT_EXTERN
))
420 tcc_error("assembler label '%s' already defined",
421 get_tok_str(label
, NULL
));
425 sym
= asm_label_push(label
);
428 put_extern_sym2(sym
, SHN_UNDEF
, 0, 0, 1);
430 esym
->st_shndx
= sh_num
;
431 esym
->st_value
= value
;
433 sym
->type
.t
&= ~VT_EXTERN
;
437 static Sym
* asm_new_label(TCCState
*s1
, int label
, int is_local
)
439 return asm_new_label1(s1
, label
, is_local
, cur_text_section
->sh_num
, ind
);
442 /* Set the value of LABEL to that of some expression (possibly
443 involving other symbols). LABEL can be overwritten later still. */
444 static Sym
* set_symbol(TCCState
*s1
, int label
)
453 esym
= elfsym(e
.sym
);
456 sym
= asm_new_label1(s1
, label
, 2, esym
? esym
->st_shndx
: SHN_ABS
, n
);
457 elfsym(sym
)->st_other
|= ST_ASM_SET
;
461 static void use_section1(TCCState
*s1
, Section
*sec
)
463 cur_text_section
->data_offset
= ind
;
464 cur_text_section
= sec
;
465 ind
= cur_text_section
->data_offset
;
468 static void use_section(TCCState
*s1
, const char *name
)
471 sec
= find_section(s1
, name
);
472 use_section1(s1
, sec
);
475 static void push_section(TCCState
*s1
, const char *name
)
477 Section
*sec
= find_section(s1
, name
);
478 sec
->prev
= cur_text_section
;
479 use_section1(s1
, sec
);
482 static void pop_section(TCCState
*s1
)
484 Section
*prev
= cur_text_section
->prev
;
486 tcc_error(".popsection without .pushsection");
487 cur_text_section
->prev
= NULL
;
488 use_section1(s1
, prev
);
491 static void asm_parse_directive(TCCState
*s1
, int global
)
493 int n
, offset
, v
, size
, tok1
;
497 /* assembler directive */
498 sec
= cur_text_section
;
500 case TOK_ASMDIR_align
:
501 case TOK_ASMDIR_balign
:
502 case TOK_ASMDIR_p2align
:
503 case TOK_ASMDIR_skip
:
504 case TOK_ASMDIR_space
:
507 n
= asm_int_expr(s1
);
508 if (tok1
== TOK_ASMDIR_p2align
)
511 tcc_error("invalid p2align, must be between 0 and 30");
513 tok1
= TOK_ASMDIR_align
;
515 if (tok1
== TOK_ASMDIR_align
|| tok1
== TOK_ASMDIR_balign
) {
516 if (n
< 0 || (n
& (n
-1)) != 0)
517 tcc_error("alignment must be a positive power of two");
518 offset
= (ind
+ n
- 1) & -n
;
520 /* the section must have a compatible alignment */
521 if (sec
->sh_addralign
< n
)
522 sec
->sh_addralign
= n
;
531 v
= asm_int_expr(s1
);
534 if (sec
->sh_type
!= SHT_NOBITS
) {
535 sec
->data_offset
= ind
;
536 ptr
= section_ptr_add(sec
, size
);
537 memset(ptr
, v
, size
);
541 case TOK_ASMDIR_quad
:
542 #ifdef TCC_TARGET_X86_64
552 if (tok
!= TOK_PPNUM
) {
554 tcc_error("64 bit constant");
556 vl
= strtoll(p
, (char **)&p
, 0);
560 if (sec
->sh_type
!= SHT_NOBITS
) {
561 /* XXX: endianness */
573 case TOK_ASMDIR_byte
:
576 case TOK_ASMDIR_word
:
577 case TOK_ASMDIR_short
:
580 case TOK_ASMDIR_long
:
588 if (sec
->sh_type
!= SHT_NOBITS
) {
591 #ifdef TCC_TARGET_X86_64
592 } else if (size
== 8) {
611 case TOK_ASMDIR_fill
:
613 int repeat
, size
, val
, i
, j
;
614 uint8_t repeat_buf
[8];
616 repeat
= asm_int_expr(s1
);
618 tcc_error("repeat < 0; .fill ignored");
625 size
= asm_int_expr(s1
);
627 tcc_error("size < 0; .fill ignored");
634 val
= asm_int_expr(s1
);
637 /* XXX: endianness */
639 repeat_buf
[1] = val
>> 8;
640 repeat_buf
[2] = val
>> 16;
641 repeat_buf
[3] = val
>> 24;
646 for(i
= 0; i
< repeat
; i
++) {
647 for(j
= 0; j
< size
; j
++) {
653 case TOK_ASMDIR_rept
:
656 TokenString
*init_str
;
658 repeat
= asm_int_expr(s1
);
659 init_str
= tok_str_alloc();
660 while (next(), tok
!= TOK_ASMDIR_endr
) {
662 tcc_error("we at end of file, .endr not found");
663 tok_str_add_tok(init_str
);
665 tok_str_add(init_str
, -1);
666 tok_str_add(init_str
, 0);
667 begin_macro(init_str
, 1);
668 while (repeat
-- > 0) {
669 tcc_assemble_internal(s1
, (parse_flags
& PARSE_FLAG_PREPROCESS
),
671 macro_ptr
= init_str
->str
;
685 esym
= elfsym(e
.sym
);
687 if (esym
->st_shndx
!= cur_text_section
->sh_num
)
688 expect("constant or same-section symbol");
692 tcc_error("attempt to .org backwards");
702 /* Also accept '.set stuff', but don't do anything with this.
703 It's used in GAS to set various features like '.set mips16'. */
705 set_symbol(s1
, tok1
);
707 case TOK_ASMDIR_globl
:
708 case TOK_ASMDIR_global
:
709 case TOK_ASMDIR_weak
:
710 case TOK_ASMDIR_hidden
:
715 sym
= get_asm_sym(tok
, NULL
);
716 if (tok1
!= TOK_ASMDIR_hidden
)
717 sym
->type
.t
&= ~VT_STATIC
;
718 if (tok1
== TOK_ASMDIR_weak
)
720 else if (tok1
== TOK_ASMDIR_hidden
)
721 sym
->a
.visibility
= STV_HIDDEN
;
724 } while (tok
== ',');
726 case TOK_ASMDIR_string
:
727 case TOK_ASMDIR_ascii
:
728 case TOK_ASMDIR_asciz
:
737 expect("string constant");
739 size
= tokc
.str
.size
;
740 if (t
== TOK_ASMDIR_ascii
&& size
> 0)
742 for(i
= 0; i
< size
; i
++)
747 } else if (tok
!= TOK_STR
) {
753 case TOK_ASMDIR_text
:
754 case TOK_ASMDIR_data
:
761 if (tok
!= ';' && tok
!= TOK_LINEFEED
) {
762 n
= asm_int_expr(s1
);
766 sprintf(sname
, "%s%d", get_tok_str(tok1
, NULL
), n
);
768 sprintf(sname
, "%s", get_tok_str(tok1
, NULL
));
769 use_section(s1
, sname
);
772 case TOK_ASMDIR_file
:
779 pstrcat(filename
, sizeof(filename
), tokc
.str
.data
);
781 pstrcat(filename
, sizeof(filename
), get_tok_str(tok
, NULL
));
782 tcc_warning_c(warn_unsupported
)("ignoring .file %s", filename
);
786 case TOK_ASMDIR_ident
:
793 pstrcat(ident
, sizeof(ident
), tokc
.str
.data
);
795 pstrcat(ident
, sizeof(ident
), get_tok_str(tok
, NULL
));
796 tcc_warning_c(warn_unsupported
)("ignoring .ident %s", ident
);
800 case TOK_ASMDIR_size
:
805 sym
= asm_label_find(tok
);
807 tcc_error("label not found: %s", get_tok_str(tok
, NULL
));
809 /* XXX .size name,label2-label1 */
810 tcc_warning_c(warn_unsupported
)("ignoring .size %s,*", get_tok_str(tok
, NULL
));
813 while (tok
!= TOK_LINEFEED
&& tok
!= ';' && tok
!= CH_EOF
) {
818 case TOK_ASMDIR_type
:
824 sym
= get_asm_sym(tok
, NULL
);
827 if (tok
== TOK_STR
) {
828 newtype
= tokc
.str
.data
;
830 if (tok
== '@' || tok
== '%')
832 newtype
= get_tok_str(tok
, NULL
);
835 if (!strcmp(newtype
, "function") || !strcmp(newtype
, "STT_FUNC")) {
836 sym
->type
.t
= (sym
->type
.t
& ~VT_BTYPE
) | VT_FUNC
;
838 tcc_warning_c(warn_unsupported
)("change type of '%s' from 0x%x to '%s' ignored",
839 get_tok_str(sym
->v
, NULL
), sym
->type
.t
, newtype
);
844 case TOK_ASMDIR_pushsection
:
845 case TOK_ASMDIR_section
:
848 int old_nb_section
= s1
->nb_sections
;
851 /* XXX: support more options */
854 while (tok
!= ';' && tok
!= TOK_LINEFEED
&& tok
!= ',') {
856 pstrcat(sname
, sizeof(sname
), tokc
.str
.data
);
858 pstrcat(sname
, sizeof(sname
), get_tok_str(tok
, NULL
));
862 /* skip section options */
865 expect("string constant");
869 if (tok
== '@' || tok
== '%')
874 last_text_section
= cur_text_section
;
875 if (tok1
== TOK_ASMDIR_section
)
876 use_section(s1
, sname
);
878 push_section(s1
, sname
);
879 /* If we just allocated a new section reset its alignment to
880 1. new_section normally acts for GCC compatibility and
881 sets alignment to PTR_SIZE. The assembler behaves different. */
882 if (old_nb_section
!= s1
->nb_sections
)
883 cur_text_section
->sh_addralign
= 1;
886 case TOK_ASMDIR_previous
:
890 if (!last_text_section
)
891 tcc_error("no previous section referenced");
892 sec
= cur_text_section
;
893 use_section1(s1
, last_text_section
);
894 last_text_section
= sec
;
897 case TOK_ASMDIR_popsection
:
901 #ifdef TCC_TARGET_I386
902 case TOK_ASMDIR_code16
:
908 case TOK_ASMDIR_code32
:
915 #ifdef TCC_TARGET_X86_64
916 /* added for compatibility with GAS */
917 case TOK_ASMDIR_code64
:
922 tcc_error("unknown assembler directive '.%s'", get_tok_str(tok
, NULL
));
928 /* assemble a file */
929 static int tcc_assemble_internal(TCCState
*s1
, int do_preprocess
, int global
)
932 int saved_parse_flags
= parse_flags
;
934 parse_flags
= PARSE_FLAG_ASM_FILE
| PARSE_FLAG_TOK_STR
;
936 parse_flags
|= PARSE_FLAG_PREPROCESS
;
941 parse_flags
|= PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
944 /* horrible gas comment */
945 while (tok
!= TOK_LINEFEED
)
947 } else if (tok
>= TOK_ASMDIR_FIRST
&& tok
<= TOK_ASMDIR_LAST
) {
948 asm_parse_directive(s1
, global
);
949 } else if (tok
== TOK_PPNUM
) {
953 n
= strtoul(p
, (char **)&p
, 10);
956 /* new local label */
957 asm_new_label(s1
, asm_get_local_label_name(s1
, n
), 1);
961 } else if (tok
>= TOK_IDENT
) {
962 /* instruction or label */
967 asm_new_label(s1
, opcode
, 0);
970 } else if (tok
== '=') {
971 set_symbol(s1
, opcode
);
974 asm_opcode(s1
, opcode
);
978 if (tok
!= ';' && tok
!= TOK_LINEFEED
)
979 expect("end of line");
980 parse_flags
&= ~PARSE_FLAG_LINEFEED
; /* XXX: suppress that hack */
983 parse_flags
= saved_parse_flags
;
987 /* Assemble the current file */
988 ST_FUNC
int tcc_assemble(TCCState
*s1
, int do_preprocess
)
992 /* default section is text */
993 cur_text_section
= text_section
;
994 ind
= cur_text_section
->data_offset
;
996 ret
= tcc_assemble_internal(s1
, do_preprocess
, 1);
997 cur_text_section
->data_offset
= ind
;
1002 /********************************************************************/
1003 /* GCC inline asm support */
1005 /* assemble the string 'str' in the current C compilation unit without
1006 C preprocessing. NOTE: str is modified by modifying the '\0' at the
1008 static void tcc_assemble_inline(TCCState
*s1
, char *str
, int len
, int global
)
1010 const int *saved_macro_ptr
= macro_ptr
;
1011 int dotid
= set_idnum('.', IS_ID
);
1012 int dolid
= set_idnum('$', 0);
1014 tcc_open_bf(s1
, ":asm:", len
);
1015 memcpy(file
->buffer
, str
, len
);
1017 tcc_assemble_internal(s1
, 0, global
);
1020 set_idnum('$', dolid
);
1021 set_idnum('.', dotid
);
1022 macro_ptr
= saved_macro_ptr
;
1025 /* find a constraint by its number or id (gcc 3 extended
1026 syntax). return -1 if not found. Return in *pp in char after the
1028 ST_FUNC
int find_constraint(ASMOperand
*operands
, int nb_operands
,
1029 const char *name
, const char **pp
)
1037 while (isnum(*name
)) {
1038 index
= (index
* 10) + (*name
) - '0';
1041 if ((unsigned)index
>= nb_operands
)
1043 } else if (*name
== '[') {
1045 p
= strchr(name
, ']');
1047 ts
= tok_alloc(name
, p
- name
);
1048 for(index
= 0; index
< nb_operands
; index
++) {
1049 if (operands
[index
].id
== ts
->tok
)
1066 static void subst_asm_operands(ASMOperand
*operands
, int nb_operands
,
1067 CString
*out_str
, CString
*in_str
)
1069 int c
, index
, modifier
;
1084 if (*str
== 'c' || *str
== 'n' ||
1085 *str
== 'b' || *str
== 'w' || *str
== 'h' || *str
== 'k' ||
1086 *str
== 'q' || *str
== 'l' ||
1087 /* P in GCC would add "@PLT" to symbol refs in PIC mode,
1088 and make literal operands not be decorated with '$'. */
1091 index
= find_constraint(operands
, nb_operands
, str
, &str
);
1093 tcc_error("invalid operand reference after %%");
1094 op
= &operands
[index
];
1095 if (modifier
== 'l') {
1096 cstr_cat(out_str
, get_tok_str(op
->is_label
, NULL
), -1);
1101 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& op
->is_memory
)
1104 subst_asm_operand(out_str
, &sv
, modifier
);
1108 cstr_ccat(out_str
, c
);
1116 static void parse_asm_operands(ASMOperand
*operands
, int *nb_operands_ptr
,
1123 nb_operands
= *nb_operands_ptr
;
1126 if (nb_operands
>= MAX_ASM_OPERANDS
)
1127 tcc_error("too many asm operands");
1128 op
= &operands
[nb_operands
++];
1132 if (tok
< TOK_IDENT
)
1133 expect("identifier");
1138 parse_mult_str(&astr
, "string constant");
1139 op
->constraint
= tcc_malloc(astr
.size
);
1140 strcpy(op
->constraint
, astr
.data
);
1145 if (!(vtop
->type
.t
& VT_ARRAY
))
1148 /* we want to avoid LLOCAL case, except when the 'm'
1149 constraint is used. Note that it may come from
1150 register storage, so we need to convert (reg)
1152 if ((vtop
->r
& VT_LVAL
) &&
1153 ((vtop
->r
& VT_VALMASK
) == VT_LLOCAL
||
1154 (vtop
->r
& VT_VALMASK
) < VT_CONST
) &&
1155 !strchr(op
->constraint
, 'm')) {
1167 *nb_operands_ptr
= nb_operands
;
1171 /* parse the GCC asm() instruction */
1172 ST_FUNC
void asm_instr(void)
1174 CString astr
, astr1
;
1175 ASMOperand operands
[MAX_ASM_OPERANDS
];
1176 int nb_outputs
, nb_operands
, i
, must_subst
, out_reg
, nb_labels
;
1177 uint8_t clobber_regs
[NB_ASM_REGS
];
1180 /* since we always generate the asm() instruction, we can ignore
1182 while (tok
== TOK_VOLATILE1
|| tok
== TOK_VOLATILE2
|| tok
== TOK_VOLATILE3
1183 || tok
== TOK_GOTO
) {
1186 parse_asm_str(&astr
);
1191 memset(clobber_regs
, 0, sizeof(clobber_regs
));
1196 parse_asm_operands(operands
, &nb_operands
, 1);
1197 nb_outputs
= nb_operands
;
1202 parse_asm_operands(operands
, &nb_operands
, 0);
1205 /* XXX: handle registers */
1211 expect("string constant");
1212 asm_clobber(clobber_regs
, tokc
.str
.data
);
1227 if (nb_operands
+ nb_labels
>= MAX_ASM_OPERANDS
)
1228 tcc_error("too many asm operands");
1229 if (tok
< TOK_UIDENT
)
1230 expect("label identifier");
1231 operands
[nb_operands
+ nb_labels
++].id
= tok
;
1233 csym
= label_find(tok
);
1235 csym
= label_push(&global_label_stack
, tok
,
1238 if (csym
->r
== LABEL_DECLARED
)
1239 csym
->r
= LABEL_FORWARD
;
1242 asmname
= asm_get_prefix_name(tcc_state
, "LG.",
1245 put_extern_sym2(csym
, SHN_UNDEF
, 0, 0, 1);
1246 get_asm_sym(asmname
, csym
);
1247 operands
[nb_operands
+ nb_labels
- 1].is_label
= asmname
;
1258 /* NOTE: we do not eat the ';' so that we can restore the current
1259 token after the assembler parsing */
1263 /* save all values in the memory */
1266 /* compute constraints */
1267 asm_compute_constraints(operands
, nb_operands
, nb_outputs
,
1268 clobber_regs
, &out_reg
);
1270 /* substitute the operands in the asm string. No substitution is
1271 done if no operands (GCC behaviour) */
1273 printf("asm: \"%s\"\n", (char *)astr
.data
);
1276 subst_asm_operands(operands
, nb_operands
+ nb_labels
, &astr1
, &astr
);
1282 printf("subst_asm: \"%s\"\n", (char *)astr1
.data
);
1285 /* generate loads */
1286 asm_gen_code(operands
, nb_operands
, nb_outputs
, 0,
1287 clobber_regs
, out_reg
);
1289 /* We don't allow switching section within inline asm to
1290 bleed out to surrounding code. */
1291 sec
= cur_text_section
;
1292 /* assemble the string with tcc internal assembler */
1293 tcc_assemble_inline(tcc_state
, astr1
.data
, astr1
.size
- 1, 0);
1294 if (sec
!= cur_text_section
) {
1295 tcc_warning("inline asm tries to change current section");
1296 use_section1(tcc_state
, sec
);
1299 /* restore the current C token */
1302 /* store the output values if needed */
1303 asm_gen_code(operands
, nb_operands
, nb_outputs
, 1,
1304 clobber_regs
, out_reg
);
1306 /* free everything */
1307 for(i
=0;i
<nb_operands
;i
++) {
1310 tcc_free(op
->constraint
);
1316 ST_FUNC
void asm_global_instr(void)
1319 int saved_nocode_wanted
= nocode_wanted
;
1321 /* Global asm blocks are always emitted. */
1324 parse_asm_str(&astr
);
1326 /* NOTE: we do not eat the ';' so that we can restore the current
1327 token after the assembler parsing */
1332 printf("asm_global: \"%s\"\n", (char *)astr
.data
);
1334 cur_text_section
= text_section
;
1335 ind
= cur_text_section
->data_offset
;
1337 /* assemble the string with tcc internal assembler */
1338 tcc_assemble_inline(tcc_state
, astr
.data
, astr
.size
- 1, 1);
1340 cur_text_section
->data_offset
= ind
;
1342 /* restore the current C token */
1346 nocode_wanted
= saved_nocode_wanted
;
1349 /********************************************************/
1351 ST_FUNC
int tcc_assemble(TCCState
*s1
, int do_preprocess
)
1353 tcc_error("asm not supported");
1356 ST_FUNC
void asm_instr(void)
1358 tcc_error("inline asm() not supported");
1361 ST_FUNC
void asm_global_instr(void)
1363 tcc_error("inline asm() not supported");
1365 #endif /* CONFIG_TCC_ASM */