| @@ -23,14 +23,20 @@ · 22 unmodified lines |
| 23 | 23 | #ifdef CONFIG_TCC_ASM |
| 24 | 24 | |
| 25 | 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 | 30 | char buf[64]; |
| 30 | | − snprintf(buf, sizeof(buf), "L..%u", n); |
| 31 | + snprintf(buf, sizeof(buf), "%s%u", prefix, n); |
| 31 | 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 | 40 | static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global); |
| 35 | 41 | static Sym* asm_new_label(TCCState *s1, int label, int is_local); |
| 36 | 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 | 1083 | modifier = 0; |
| 1078 | 1084 | if (*str == 'c' || *str == 'n' || |
| 1079 | 1085 | *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' || |
| 1080 | | − *str == 'q' || |
| 1086 | + *str == 'q' || *str == 'l' || |
| 1081 | 1087 | /* P in GCC would add "@PLT" to symbol refs in PIC mode, |
| 1082 | 1088 | and make literal operands not be decorated with '$'. */ |
| 1083 | 1089 | *str == 'P') |
| @@ -1086,13 +1092,17 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands, · 2 unmodified lines |
| 1086 | 1092 | if (index < 0) |
| 1087 | 1093 | tcc_error("invalid operand reference after %%"); |
| 1088 | 1094 | op = &operands[index]; |
| 1089 | | − sv = *op->vt; |
| 1090 | | − if (op->reg >= 0) { |
| 1091 | | − sv.r = op->reg; |
| 1092 | | − if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) |
| 1093 | | − sv.r |= VT_LVAL; |
| 1095 | + if (modifier == 'l') { |
| 1096 | + cstr_cat(out_str, get_tok_str(op->is_label, NULL), -1); |
| 1097 | + } else { |
| 1098 | + sv = *op->vt; |
| 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 | 1106 | } else { |
| 1097 | 1107 | add_char: |
| 1098 | 1108 | cstr_ccat(out_str, c); |
| @@ -1163,18 +1173,20 @@ ST_FUNC void asm_instr(void) · 64 unmodified lines |
| 1163 | 1173 | { |
| 1164 | 1174 | CString astr, astr1; |
| 1165 | 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 | 1177 | uint8_t clobber_regs[NB_ASM_REGS]; |
| 1168 | 1178 | Section *sec; |
| 1169 | 1179 | |
| 1170 | 1180 | /* since we always generate the asm() instruction, we can ignore |
| 1171 | 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 | 1184 | next(); |
| 1174 | 1185 | } |
| 1175 | 1186 | parse_asm_str(&astr); |
| 1176 | 1187 | nb_operands = 0; |
| 1177 | 1188 | nb_outputs = 0; |
| 1189 | + nb_labels = 0; |
| 1178 | 1190 | must_subst = 0; |
| 1179 | 1191 | memset(clobber_regs, 0, sizeof(clobber_regs)); |
| 1180 | 1192 | if (tok == ':') { |
| @@ -1193,6 +1205,8 @@ ST_FUNC void asm_instr(void) · 12 unmodified lines |
| 1193 | 1205 | /* XXX: handle registers */ |
| 1194 | 1206 | next(); |
| 1195 | 1207 | for(;;) { |
| 1208 | + if (tok == ':') |
| 1209 | + break; |
| 1196 | 1210 | if (tok != TOK_STR) |
| 1197 | 1211 | expect("string constant"); |
| 1198 | 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 | 1273 | printf("asm: \"%s\"\n", (char *)astr.data); |
| 1227 | 1274 | #endif |
| 1228 | 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 | 1277 | cstr_free(&astr); |
| 1231 | 1278 | } else { |
| 1232 | 1279 | astr1 = astr; |