endbr64 has no operand but comes with a ModR/M byte. Handle it in the same way as *fence instructions.
Unified · Split
| @@ -1002,15 +1002,21 @@ again: · 1001 unmodified lines | ||
| 1002 | 1002 | modrm_index = -1; |
| 1003 | 1003 | modreg_index = -1; |
| 1004 | 1004 | if (pa->instr_type & OPC_MODRM) { |
| 1005 | +#ifdef TCC_TARGET_X86_64 | |
| 1005 | 1006 | if (!nb_ops) { |
| 1006 | 1007 | /* A modrm opcode without operands is a special case (e.g. mfence). |
| 1007 | − It has a group and acts as if there's an register operand 0 | |
| 1008 | − (ax). */ | |
| 1008 | + It has a group and acts as if there's an register operand 0 */ | |
| 1009 | 1009 | i = 0; |
| 1010 | 1010 | ops[i].type = OP_REG; |
| 1011 | − ops[i].reg = 0; | |
| 1011 | + if (pa->sym == TOK_ASM_endbr64) | |
| 1012 | + ops[i].reg = 2; // dx | |
| 1013 | + else if (pa->sym >= TOK_ASM_lfence && pa->sym <= TOK_ASM_sfence) | |
| 1014 | + ops[i].reg = 0; // ax | |
| 1015 | + else | |
| 1016 | + tcc_error("bad MODR/M opcode without operands"); | |
| 1012 | 1017 | goto modrm_found; |
| 1013 | 1018 | } |
| 1019 | +#endif | |
| 1014 | 1020 | /* first look for an ea operand */ |
| 1015 | 1021 | for(i = 0;i < nb_ops; i++) { |
| 1016 | 1022 | if (op_type[i] & OP_EA) |
| @@ -538,6 +538,9 @@ ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) · 537 unmodified lines | ||
| 538 | 538 | DEF_ASM_OP0L(mfence, 0x0fae, 6, OPC_MODRM) |
| 539 | 539 | DEF_ASM_OP0L(sfence, 0x0fae, 7, OPC_MODRM) |
| 540 | 540 | DEF_ASM_OP1(clflush, 0x0fae, 7, OPC_MODRM, OPT_EA) |
| 541 | + | |
| 542 | + /* Control-Flow Enforcement */ | |
| 543 | + DEF_ASM_OP0L(endbr64, 0xf30f1e, 7, OPC_MODRM) | |
| 541 | 544 | #undef ALT |
| 542 | 545 | #undef DEF_ASM_OP0 |
| 543 | 546 | #undef DEF_ASM_OP0L |