diff --git a/README.md b/README.md index 7df39a2df..5fe9c0a43 100644 --- a/README.md +++ b/README.md @@ -229,7 +229,7 @@ static class HowTo_Assemble { // To broadcast memory, use the __dword_bcst/__qword_bcst memory types c.vunpcklps(xmm2.k5.z, xmm6, __dword_bcst[rax]); - // You can create anonymous labels, just like in eg. masm @F and @B + // You can create anonymous labels, just like in eg. masm, @@, @F and @B c.AnonymousLabel(); // same as @@: in masm c.inc(rax); c.je(c.@B); // reference the previous anonymous label diff --git a/src/csharp/Intel/Iced.UnitTests/Intel/AssemblerTests/AssemblerLabelTests.cs b/src/csharp/Intel/Iced.UnitTests/Intel/AssemblerTests/AssemblerLabelTests.cs index 53a4bba24..bd0f4821f 100644 --- a/src/csharp/Intel/Iced.UnitTests/Intel/AssemblerTests/AssemblerLabelTests.cs +++ b/src/csharp/Intel/Iced.UnitTests/Intel/AssemblerTests/AssemblerLabelTests.cs @@ -45,41 +45,41 @@ namespace Iced.UnitTests.Intel.AssemblerTests { [Fact] void Anonymous_labels() { - var c = new Assembler(64); + var c = new Assembler(64); - var lbl1 = c.CreateLabel(); - var lbl2 = c.CreateLabel(); - var lbl3 = c.CreateLabel(); - var lbl4 = c.CreateLabel(); + var lbl1 = c.CreateLabel(); + var lbl2 = c.CreateLabel(); + var lbl3 = c.CreateLabel(); + var lbl4 = c.CreateLabel(); - c.Label(ref lbl1); - c.inc(eax); - c.nop(); - c.AnonymousLabel(); - c.je(c.@B); - c.nop(); - c.Label(ref lbl2); - c.je(c.@B); - c.nop(); - c.jmp(lbl1); - c.nop(); - c.jmp(lbl2); - c.nop(); - c.jmp(lbl3); - c.nop(); - c.jmp(lbl4); - c.nop(); - c.jne(c.@F); - c.nop(); - c.Label(ref lbl3); - c.jne(c.@F); - c.nop(); - c.AnonymousLabel(); - c.inc(eax); - c.nop(); - c.Label(ref lbl4); - c.nop(); - c.nop(); + c.Label(ref lbl1); + c.inc(eax); + c.nop(); + c.AnonymousLabel(); + c.je(c.@B); + c.nop(); + c.Label(ref lbl2); + c.je(c.@B); + c.nop(); + c.jmp(lbl1); + c.nop(); + c.jmp(lbl2); + c.nop(); + c.jmp(lbl3); + c.nop(); + c.jmp(lbl4); + c.nop(); + c.jne(c.@F); + c.nop(); + c.Label(ref lbl3); + c.jne(c.@F); + c.nop(); + c.AnonymousLabel(); + c.inc(eax); + c.nop(); + c.Label(ref lbl4); + c.nop(); + c.nop(); var expectedData = new byte[] { 0xFF, 0xC0, 0x90, 0x74, 0xFE, 0x90, 0x74, 0xFB, 0x90, 0xEB, 0xF5, 0x90, 0xEB, 0xF8, 0x90, 0xEB, @@ -98,6 +98,22 @@ namespace Iced.UnitTests.Intel.AssemblerTests { Assert.Throws(() => c.Assemble(new CodeWriterImpl(), 0)); } + [Fact] + void Undeclared_forward_anon_label_throws() { + var c = new Assembler(64); + c.nop(); + c.je(c.@F); + Assert.Throws(() => c.Assemble(new CodeWriterImpl(), 0)); + } + + [Fact] + void At_most_one_anon_label_per_instruction() { + var c = new Assembler(64); + c.nop(); + c.AnonymousLabel(); + Assert.Throws(() => c.AnonymousLabel()); + } + [Fact] void Referencing_backward_anon_label_when_not_defined_throws() { var c = new Assembler(64); diff --git a/src/csharp/Intel/Iced/Intel/Assembler/Assembler.cs b/src/csharp/Intel/Iced/Intel/Assembler/Assembler.cs index 0b63231cd..faeafbe17 100644 --- a/src/csharp/Intel/Iced/Intel/Assembler/Assembler.cs +++ b/src/csharp/Intel/Iced/Intel/Assembler/Assembler.cs @@ -127,10 +127,12 @@ namespace Iced.Intel { } /// - /// Creates an anonymous label that can be referenced by using the (backward anonymous label) + /// Creates an anonymous label that can be referenced by using (backward anonymous label) /// and (forward anonymous label). /// public void AnonymousLabel() { + if (_definedAnonLabel) + throw new InvalidOperationException("At most one anonymous label per instruction is allowed"); if (_nextAnonLabel.IsEmpty) _currentAnonLabel = CreateLabel(); else @@ -478,6 +480,11 @@ namespace Iced.Intel { return false; } + if (!_nextAnonLabel.IsEmpty) { + errorMessage = "Found an @F anonymous label reference but there was no call to " + nameof(AnonymousLabel); + return false; + } + var blocks = new[] { new InstructionBlock(writer, _instructions, rip) }; if (BlockEncoder.TryEncode(Bitness, blocks, out errorMessage, out var blockResults, options)) { assemblerResult = new AssemblerResult(blockResults);