| @@ -23,14 +23,20 @@ · 22 unmodified lines |
| 23 | #ifdef CONFIG_TCC_ASM | 23 | #ifdef CONFIG_TCC_ASM |
| 24 | | 24 | |
| 25 | static Section *last_text_section; /* to handle .previous asm directive */ | 25 | static Section *last_text_section; /* to handle .previous asm directive */ |
| | 26 | static int asmgoto_n; |
| 26 | | 27 | |
| 27 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) | 28 | static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n) |
| 28 | { | 29 | { |
| 29 | char buf[64]; | 30 | char buf[64]; |
| 30 | snprintf(buf, sizeof(buf), "L..%u", n); | 31 | snprintf(buf, sizeof(buf), "%s%u", prefix, n); |
| 31 | return tok_alloc_const(buf); | 32 | return tok_alloc_const(buf); |
| 32 | } | 33 | } |
| 33 | | 34 | |
| | 35 | ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
| | 36 | { |
| | 37 | return asm_get_prefix_name(s1, "L..", n); |
| | 38 | } |
| | 39 | |
| 34 | static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); | 40 | 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); | 41 | 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); | 42 | static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value); |
| @@ -1077,7 +1083,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 1040 unmodified lines |
| 1077 | modifier = 0; | 1083 | modifier = 0; |
| 1078 | if (*str == 'c' || *str == 'n' || | 1084 | if (*str == 'c' || *str == 'n' || |
| 1079 | *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || | 1085 | *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || |
| 1080 | *str == 'q' || | 1086 | *str == 'q' || *str == 'l' || |
| 1081 | /* P in GCC would add "@PLT" to symbol refs in PIC mode, | 1087 | /* P in GCC would add "@PLT" to symbol refs in PIC mode, |
| 1082 | and make literal operands not be decorated with '$'. */ | 1088 | and make literal operands not be decorated with '$'. */ |
| 1083 | *str == 'P') | 1089 | *str == 'P') |
| @@ -1086,13 +1092,17 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 2 unmodified lines |
| 1086 | if (index < 0) | 1092 | if (index < 0) |
| 1087 | tcc_error("invalid operand reference after %%"); | 1093 | tcc_error("invalid operand reference after %%"); |
| 1088 | op = &operands[index]; | 1094 | op = &operands[index]; |
| 1089 | sv = *op->vt; | 1095 | if (modifier == 'l') { |
| 1090 | if (op->reg >= 0) { | 1096 | cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1); |
| 1091 | sv.r = op->reg; | 1097 | } else { |
| 1092 | if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) | 1098 | sv = *op->vt; |
| 1093 | sv.r |= VT_LVAL; | 1099 | if (op->reg >= 0) { |
| | 1100 | sv.r = op->reg; |
| | 1101 | if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) |
| | 1102 | sv.r |= VT_LVAL; |
| | 1103 | } |
| | 1104 | subst_asm_operand(out_str, &sv, modifier); |
| 1094 | } | 1105 | } |
| 1095 | subst_asm_operand(out_str, &sv, modifier); | | |
| 1096 | } else { | 1106 | } else { |
| 1097 | add_char: | 1107 | add_char: |
| 1098 | cstr_ccat(out_str, c); | 1108 | cstr_ccat(out_str, c); |
| @@ -1163,18 +1173,20 @@ ST_FUNC void asm_instr(void) · 64 unmodified lines |
| 1163 | { | 1173 | { |
| 1164 | CString astr, astr1; | 1174 | CString astr, astr1; |
| 1165 | ASMOperand operands[MAX_ASM_OPERANDS]; | 1175 | ASMOperand operands[MAX_ASM_OPERANDS]; |
| 1166 | int nb_outputs, nb_operands, i, must_subst, out_reg; | 1176 | int nb_outputs, nb_operands, i, must_subst, out_reg, nb_labels; |
| 1167 | uint8_t clobber_regs[NB_ASM_REGS]; | 1177 | uint8_t clobber_regs[NB_ASM_REGS]; |
| 1168 | Section *sec; | 1178 | Section *sec; |
| 1169 | | 1179 | |
| 1170 | /* since we always generate the asm() instruction, we can ignore | 1180 | /* since we always generate the asm() instruction, we can ignore |
| 1171 | volatile */ | 1181 | volatile */ |
| 1172 | if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) { | 1182 | while (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3 |
| | 1183 | || tok == TOK_GOTO) { |
| 1173 | next(); | 1184 | next(); |
| 1174 | } | 1185 | } |
| 1175 | parse_asm_str(&astr); | 1186 | parse_asm_str(&astr); |
| 1176 | nb_operands = 0; | 1187 | nb_operands = 0; |
| 1177 | nb_outputs = 0; | 1188 | nb_outputs = 0; |
| | 1189 | nb_labels = 0; |
| 1178 | must_subst = 0; | 1190 | must_subst = 0; |
| 1179 | memset(clobber_regs, 0, sizeof(clobber_regs)); | 1191 | memset(clobber_regs, 0, sizeof(clobber_regs)); |
| 1180 | if (tok == ':') { | 1192 | if (tok == ':') { |
| @@ -1193,6 +1205,8 @@ ST_FUNC void asm_instr(void) · 12 unmodified lines |
| 1193 | /* XXX: handle registers */ | 1205 | /* XXX: handle registers */ |
| 1194 | next(); | 1206 | next(); |
| 1195 | for(;;) { | 1207 | for(;;) { |
| | 1208 | if (tok == ':') |
| | 1209 | break; |
| 1196 | if (tok != TOK_STR) | 1210 | if (tok != TOK_STR) |
| 1197 | expect("string constant"); | 1211 | expect("string constant"); |
| 1198 | asm_clobber(clobber_regs, tokc.str.data); | 1212 | asm_clobber(clobber_regs, tokc.str.data); |
| @@ -1204,6 +1218,39 @@ ST_FUNC void asm_instr(void) · 5 unmodified lines |
| 1204 | } | 1218 | } |
| 1205 | } | 1219 | } |
| 1206 | } | 1220 | } |
| | 1221 | if (tok == ':') { |
| | 1222 | /* goto labels */ |
| | 1223 | next(); |
| | 1224 | for (;;) { |
| | 1225 | Sym *csym; |
| | 1226 | int asmname; |
| | 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; |
| | 1232 | |
| | 1233 | csym = label_find(tok); |
| | 1234 | if (!csym) { |
| | 1235 | csym = label_push(&global_label_stack, tok, |
| | 1236 | LABEL_FORWARD); |
| | 1237 | } else { |
| | 1238 | if (csym->r == LABEL_DECLARED) |
| | 1239 | csym->r = LABEL_FORWARD; |
| | 1240 | } |
| | 1241 | next(); |
| | 1242 | asmname = asm_get_prefix_name(tcc_state, "LG.", |
| | 1243 | ++asmgoto_n); |
| | 1244 | if (!csym->c) |
| | 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; |
| | 1248 | |
| | 1249 | if (tok != ',') |
| | 1250 | break; |
| | 1251 | next(); |
| | 1252 | } |
| | 1253 | } |
| 1207 | } | 1254 | } |
| 1208 | } | 1255 | } |
| 1209 | } | 1256 | } |
| @@ -1226,7 +1273,7 @@ ST_FUNC void asm_instr(void) · 16 unmodified lines |
| 1226 | printf("asm: \"%s\"\n", (char *)astr.data); | 1273 | printf("asm: \"%s\"\n", (char *)astr.data); |
| 1227 | #endif | 1274 | #endif |
| 1228 | if (must_subst) { | 1275 | if (must_subst) { |
| 1229 | subst_asm_operands(operands, nb_operands, &astr1, &astr); | 1276 | subst_asm_operands(operands, nb_operands + nb_labels, &astr1, &astr); |
| 1230 | cstr_free(&astr); | 1277 | cstr_free(&astr); |
| 1231 | } else { | 1278 | } else { |
| 1232 | astr1 = astr; | 1279 | astr1 = astr; |