diff --git a/src/iasm.c b/src/iasm.c index 6d5315b596c3..d91fdf115a7f 100644 --- a/src/iasm.c +++ b/src/iasm.c @@ -1383,38 +1383,45 @@ static code *asm_emit(Loc loc, popndTmp->pregDisp2 && popndTmp->pregDisp2->val == _BP) usDefaultseg = _SS; + else if (asmstate.ucItype == ITjump) + usDefaultseg = _CS; else usDefaultseg = _DS; if (pregSegment->val != usDefaultseg) - switch (pregSegment->val) - { - case _CS: - emit(0x2e); - pc->Iflags |= CFcs; - break; - case _SS: - emit(0x36); - pc->Iflags |= CFss; - break; - case _DS: - emit(0x3e); - pc->Iflags |= CFds; - break; - case _ES: - emit(0x26); - pc->Iflags |= CFes; - break; - case _FS: - emit(0x64); - pc->Iflags |= CFfs; - break; - case _GS: - emit(0x65); - pc->Iflags |= CFgs; - break; - default: - assert(0); - } + { + if (asmstate.ucItype == ITjump) + error(asmstate.loc, "Cannot generate a segment prefix for a branching instruction"); + else + switch (pregSegment->val) + { + case _CS: + emit(0x2e); + pc->Iflags |= CFcs; + break; + case _SS: + emit(0x36); + pc->Iflags |= CFss; + break; + case _DS: + emit(0x3e); + pc->Iflags |= CFds; + break; + case _ES: + emit(0x26); + pc->Iflags |= CFes; + break; + case _FS: + emit(0x64); + pc->Iflags |= CFfs; + break; + case _GS: + emit(0x65); + pc->Iflags |= CFgs; + break; + default: + assert(0); + } + } } break; } @@ -4311,6 +4318,8 @@ static OPND *asm_primary_exp() o1->segreg = regp; asm_token(); o2 = asm_cond_exp(); + if (o2->s && o2->s->isLabel()) + o2->segreg = NULL; // The segment register was specified explicitly. o1 = asm_merge_opnds(o1, o2); } else if (asm_TKlbra_seen) @@ -4354,23 +4363,18 @@ static OPND *asm_primary_exp() } else { - if (asmstate.ucItype == ITjump) - { - s = NULL; - if (asmstate.sc->func->labtab) - s = asmstate.sc->func->labtab->lookup(asmtok->ident); - if (!s) - s = asmstate.sc->search(Loc(), asmtok->ident, &scopesym); - if (!s) - { - // Assume it is a label, and define that label - s = asmstate.sc->func->searchLabel(asmtok->ident); - } - } - else + s = NULL; + if (asmstate.sc->func->labtab) + s = asmstate.sc->func->labtab->lookup(asmtok->ident); + if (!s) s = asmstate.sc->search(Loc(), asmtok->ident, &scopesym); if (!s) - asmerr("undefined identifier '%s'", asmtok->toChars()); + { + // Assume it is a label, and define that label + s = asmstate.sc->func->searchLabel(asmtok->ident); + } + if (s->isLabel()) + o1->segreg = ®tab[25]; // Make it use CS as a base for a label Identifier *id = asmtok->ident; asm_token(); diff --git a/test/compilable/iasm_labeloperand.d b/test/compilable/iasm_labeloperand.d new file mode 100644 index 000000000000..f46ba00edd19 --- /dev/null +++ b/test/compilable/iasm_labeloperand.d @@ -0,0 +1,35 @@ + +version (D_InlineAsm_X86) + version = TestInlineAsm; +else version (D_InlineAsm_X86_64) + version = TestInlineAsm; +else + pragma(msg, "Inline asm not supported, not testing."); + +version (TestInlineAsm) +{ + void testInlineAsm() + { + asm + { + L1: + nop; + nop; + nop; + nop; + + mov EAX, dword ptr L1; // Check back references + mov EAX, dword ptr L2; // Check forward references + mov EAX, dword ptr DS:L1; // Not really useful in standard use, but who knows. + mov EAX, dword ptr FS:L2; // Once again, not really useful, but it is valid. + mov EAX, dword ptr CS:L1; // This is what the first test case should implicitly be. + + L2: + nop; + nop; + nop; + nop; + + } + } +} diff --git a/test/fail_compilation/fail12635.d b/test/fail_compilation/fail12635.d new file mode 100644 index 000000000000..b00cc47b3009 --- /dev/null +++ b/test/fail_compilation/fail12635.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail12635.d(19): Error: Cannot generate a segment prefix for a branching instruction +--- +*/ + +void foo() +{ + enum NOP = 0x9090_9090_9090_9090; + + asm + { + L1: + dq NOP,NOP,NOP,NOP; // 32 + dq NOP,NOP,NOP,NOP; // 64 + dq NOP,NOP,NOP,NOP; // 96 + dq NOP,NOP,NOP,NOP; // 128 + jmp DS:L1; + } +}