blob: b35a2b7f651b430eddbf0479e883f74417c17b6e [file] [log] [blame]
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "syzygy/assm/assembler.h"
#include <vector>
#include "gtest/gtest.h"
#include "syzygy/core/disassembler_util.h"
namespace assm {
typedef AssemblerImpl::Immediate Immediate;
typedef AssemblerImpl::Operand Operand;
typedef AssemblerImpl::Displacement Displacement;
typedef AssemblerImpl::Label Label;
namespace {
class TestSerializer : public AssemblerImpl::InstructionSerializer {
public:
struct Reference {
uint32_t location;
const void* ref;
};
struct Instruction {
uint32_t location;
size_t size;
// Position in code.
size_t position;
};
TestSerializer() {
}
virtual void AppendInstruction(uint32_t location,
const uint8_t* bytes,
size_t num_bytes,
const AssemblerImpl::ReferenceInfo* refs,
size_t num_refs) {
// Note the location of this instruction.
Instruction instr = { location, num_bytes, code.size() };
instructions.push_back(instr);
for (size_t i = 0; i < num_refs; ++i) {
Reference ref = { code.size() + refs[i].offset, refs[i].reference };
references.push_back(ref);
}
code.insert(code.end(), bytes, bytes + num_bytes);
}
virtual bool FinalizeLabel(uint32_t location,
const uint8_t* bytes,
size_t num_bytes) {
// Find the instruction that's being amended.
for (auto instr: instructions) {
if (instr.location <= location &&
instr.location + instr.size > location) {
// Make sure the amended bytes are flush against the end of the
// instruction.
EXPECT_EQ(instr.location + instr.size, location + num_bytes);
size_t pos = instr.position + location - instr.location;
for (size_t i = 0; i < num_bytes; ++i)
code.at(pos + i) = bytes[i];
return true;
}
}
ADD_FAILURE() << "FinalizeLabel targeting data outside instructions.";
return false;
}
std::vector<uint8_t> code;
std::vector<Instruction> instructions;
std::vector<Reference> references;
};
class AssemblerTest : public testing::Test {
public:
AssemblerTest() : asm_(0, &serializer_) {
}
TestSerializer serializer_;
AssemblerImpl asm_;
};
#define EXPECT_BYTES(...) \
do { \
uint8_t data[] = {__VA_ARGS__}; \
ASSERT_EQ(arraysize(data), serializer_.code.size()); \
EXPECT_EQ(0, memcmp(data, &serializer_.code.at(0), arraysize(data))); \
serializer_.code.clear(); \
} while (0)
template <typename ValueImpl>
class ValueTest : public AssemblerTest {
public:
typedef ValueImpl ValueImpl;
};
typedef ::testing::Types<Immediate, Displacement> ValueTestTypes;
TYPED_TEST_CASE(ValueTest, ValueTestTypes);
} // namespace
TYPED_TEST(ValueTest, ValueImpl) {
ValueImpl imm1;
EXPECT_EQ(0, imm1.value());
EXPECT_EQ(NULL, imm1.reference());
EXPECT_EQ(kSizeNone, imm1.size());
EXPECT_TRUE(imm1 == imm1);
ValueImpl imm2(0xCAFEBABE, kSize32Bit);
EXPECT_EQ(0xCAFEBABE, imm2.value());
EXPECT_EQ(NULL, imm2.reference());
EXPECT_EQ(kSize32Bit, imm2.size());
EXPECT_TRUE(imm2 == imm2);
EXPECT_FALSE(imm2 == imm1);
int ref2 = 0;
ValueImpl imm3(0xCAFEBABE, kSize32Bit, &ref2);
EXPECT_EQ(0xCAFEBABE, imm3.value());
EXPECT_EQ(&ref2, imm3.reference());
EXPECT_EQ(kSize32Bit, imm3.size());
EXPECT_TRUE(imm3 == imm3);
EXPECT_FALSE(imm3 == imm2);
EXPECT_FALSE(imm3 == imm1);
ValueImpl imm4(0xCAFEBABE, kSize32Bit, &ref2);
EXPECT_TRUE(imm4 == imm3);
}
TEST_F(AssemblerTest, OperandImpl) {
{
Operand op(edi);
EXPECT_EQ(kRegisterEdi, op.base());
EXPECT_EQ(kRegisterNone, op.index());
EXPECT_EQ(kTimes1, op.scale());
EXPECT_EQ(0, op.displacement().value());
EXPECT_EQ(NULL, op.displacement().reference());
EXPECT_EQ(kSizeNone, op.displacement().size());
}
{
int ref = 0;
Operand op(ecx, Displacement(0xCAFEBABE, kSize32Bit, &ref));
EXPECT_EQ(kRegisterEcx, op.base());
EXPECT_EQ(kRegisterNone, op.index());
EXPECT_EQ(kTimes1, op.scale());
EXPECT_EQ(0xCAFEBABE, op.displacement().value());
EXPECT_EQ(&ref, op.displacement().reference());
EXPECT_EQ(kSize32Bit, op.displacement().size());
}
{
int ref = 0;
Operand op(Displacement(0xCAFEBABE, kSize32Bit, &ref));
EXPECT_EQ(kRegisterNone, op.base());
EXPECT_EQ(kRegisterNone, op.index());
EXPECT_EQ(kTimes1, op.scale());
EXPECT_EQ(0xCAFEBABE, op.displacement().value());
EXPECT_EQ(&ref, op.displacement().reference());
EXPECT_EQ(kSize32Bit, op.displacement().size());
}
{
Operand op(ebp, ecx, kTimes8);
EXPECT_EQ(kRegisterEbp, op.base());
EXPECT_EQ(kRegisterEcx, op.index());
EXPECT_EQ(kTimes8, op.scale());
EXPECT_EQ(0, op.displacement().value());
EXPECT_EQ(NULL, op.displacement().reference());
EXPECT_EQ(kSizeNone, op.displacement().size());
}
{
int ref = 0;
Operand op(ebp, ecx, kTimes2, Displacement(0xCA, kSize8Bit, &ref));
EXPECT_EQ(kRegisterEbp, op.base());
EXPECT_EQ(kRegisterEcx, op.index());
EXPECT_EQ(kTimes2, op.scale());
EXPECT_EQ(0xCA, op.displacement().value());
EXPECT_EQ(&ref, op.displacement().reference());
EXPECT_EQ(kSize8Bit, op.displacement().size());
}
}
TEST_F(AssemblerTest, Nop) {
asm_.nop(0);
EXPECT_TRUE(serializer_.code.empty());
// NOPs are generated in bunches of instructions of up to 15 bytes in
// length. We validate that each one of them is in fact a sequence of NOPs.
for (size_t i = 1; i <= 15; ++i) {
asm_.nop(i);
EXPECT_EQ(i, serializer_.code.size());
// The sequence of bytes should consist of NOP instructions.
size_t j = 0;
size_t instruction_count = 0;
while (j < i) {
_DInst instruction = {};
ASSERT_TRUE(core::DecodeOneInstruction(serializer_.code.data() + j,
i - j,
&instruction));
ASSERT_TRUE(core::IsNop(instruction));
j += instruction.size;
++instruction_count;
}
// 1 or 2 instructions should be generated.
ASSERT_LT(0u, instruction_count);
ASSERT_GE(2u, instruction_count);
serializer_.code.clear();
}
}
TEST_F(AssemblerTest, Call) {
asm_.set_location(0xCAFEBABE);
// Immediate call.
asm_.call(Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0xE8, 0xFB, 0xFF, 0xFF, 0xFF);
// Indirect call - we test only one operand encoding, as the others
// are well covered in the mov instruction.
asm_.call(Operand(Displacement(0xCAFEBABE, kSize32Bit, NULL)));
EXPECT_BYTES(0xFF, 0x15, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, Jmp) {
asm_.set_location(0xCAFEBABE);
// Immediate 8-bit reach jmp.
asm_.jmp(Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0xEB, 0xFE);
ASSERT_EQ(1, kShortJumpOpcodeSize);
ASSERT_EQ(2, kShortJumpSize);
// Immediate 32-bit reach jmp.
asm_.jmp(Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0xE9, 0xF9, 0xFF, 0xFF, 0xFF);
ASSERT_EQ(1, kLongJumpOpcodeSize);
ASSERT_EQ(5, kLongJumpSize);
// Indirect jmp - we test only one operand encoding, as the others
// are well covered in the mov instruction.
asm_.jmp(Operand(Displacement(0xCAFEBABE, kSize32Bit, NULL)));
EXPECT_BYTES(0xFF, 0x25, 0xBE, 0xBA, 0xFE, 0xCA);
// Register 32-bit jmp.
asm_.jmp(ebx);
EXPECT_BYTES(0xFF, 0xE3);
}
TEST_F(AssemblerTest, Ret) {
asm_.ret();
EXPECT_BYTES(0xC3);
asm_.ret(0x4);
EXPECT_BYTES(0xC2, 0x04, 0x00);
}
TEST_F(AssemblerTest, MovByte) {
asm_.mov_b(Operand(eax, ebx, kTimes4,
Displacement(0xCAFEBABE, kSize32Bit)),
Immediate(0xCB, kSize8Bit));
EXPECT_BYTES(0xC6, 0x84, 0x98, 0xBE, 0xBA, 0xFE, 0xCA, 0xCB);
}
TEST_F(AssemblerTest, MovzxByte) {
asm_.movzx_b(eax, Operand(ebx));
EXPECT_BYTES(0x0F, 0xB6, 0x03);
asm_.movzx_b(ecx, Operand(ecx, edx, kTimes2));
EXPECT_BYTES(0x0F, 0xB6, 0x0C, 0x51);
}
TEST_F(AssemblerTest, MovImmediate) {
// Immediate moves.
asm_.mov(eax, Immediate(0xCAFEBABE, kSize32Bit));
EXPECT_BYTES(0xB8, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(ebx, Immediate(0xCAFEBABE, kSize32Bit));
EXPECT_BYTES(0xBB, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, MovRegisterToRegister) {
// Register to register, one case each for source and dst.
asm_.mov(eax, ebx);
EXPECT_BYTES(0x8B, 0xC3);
asm_.mov(ecx, eax);
EXPECT_BYTES(0x8B, 0xC8);
asm_.mov(ebx, eax);
EXPECT_BYTES(0x8B, 0xD8);
asm_.mov(edx, eax);
EXPECT_BYTES(0x8B, 0xD0);
asm_.mov(esp, eax);
EXPECT_BYTES(0x8B, 0xE0);
asm_.mov(ebp, eax);
EXPECT_BYTES(0x8B, 0xE8);
asm_.mov(esi, eax);
EXPECT_BYTES(0x8B, 0xF0);
asm_.mov(edi, eax);
EXPECT_BYTES(0x8B, 0xF8);
asm_.mov(ebx, eax);
EXPECT_BYTES(0x8B, 0xD8);
asm_.mov(eax, ecx);
EXPECT_BYTES(0x8B, 0xC1);
asm_.mov(eax, ebx);
EXPECT_BYTES(0x8B, 0xC3);
asm_.mov(eax, edx);
EXPECT_BYTES(0x8B, 0xC2);
asm_.mov(eax, esp);
EXPECT_BYTES(0x8B, 0xC4);
asm_.mov(eax, ebp);
EXPECT_BYTES(0x8B, 0xC5);
asm_.mov(eax, esi);
EXPECT_BYTES(0x8B, 0xC6);
asm_.mov(eax, edi);
EXPECT_BYTES(0x8B, 0xC7);
}
TEST_F(AssemblerTest, MovRegisterIndirect) {
// Indirect register only source modes.
asm_.mov(ebx, Operand(eax));
EXPECT_BYTES(0x8B, 0x18);
asm_.mov(eax, Operand(ecx));
EXPECT_BYTES(0x8B, 0x01);
asm_.mov(edx, Operand(ebx));
EXPECT_BYTES(0x8B, 0x13);
asm_.mov(ecx, Operand(edx));
EXPECT_BYTES(0x8B, 0x0A);
// Note that EBP is a special case that always requires a displacement.
asm_.mov(ebx, Operand(ebp));
EXPECT_BYTES(0x8B, 0x5D, 0x00);
// Note that ESP is a special case that always requires a SIB byte.
asm_.mov(ecx, Operand(esp));
EXPECT_BYTES(0x8B, 0x0C, 0x24);
asm_.mov(ebx, Operand(esi));
EXPECT_BYTES(0x8B, 0x1E);
asm_.mov(eax, Operand(edi));
EXPECT_BYTES(0x8B, 0x07);
// Indirect register destination modes.
asm_.mov(Operand(eax), ebx);
EXPECT_BYTES(0x89, 0x18);
asm_.mov(Operand(ecx), eax);
EXPECT_BYTES(0x89, 0x01);
asm_.mov(Operand(ebx), edx);
EXPECT_BYTES(0x89, 0x13);
asm_.mov(Operand(edx), ecx);
EXPECT_BYTES(0x89, 0x0A);
// Note that EBP is a special case that always requires a displacement.
asm_.mov(Operand(ebp), ebx);
EXPECT_BYTES(0x89, 0x5D, 0x00);
// Note that ESP is a special case that always requires a SIB byte.
asm_.mov(Operand(esp), ecx);
EXPECT_BYTES(0x89, 0x0C, 0x24);
asm_.mov(Operand(esi), ebx);
EXPECT_BYTES(0x89, 0x1E);
asm_.mov(Operand(edi), eax);
EXPECT_BYTES(0x89, 0x07);
}
TEST_F(AssemblerTest, MovRegisterDisplacementIndirect) {
// Register & displacement source modes.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
asm_.mov(ebx, Operand(eax, cafebabe));
EXPECT_BYTES(0x8B, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ecx, cafebabe));
EXPECT_BYTES(0x8B, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ebx, cafebabe));
EXPECT_BYTES(0x8B, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(edx, cafebabe));
EXPECT_BYTES(0x8B, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ebp, cafebabe));
EXPECT_BYTES(0x8B, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.mov(eax, Operand(esp, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x24, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(esi, cafebabe));
EXPECT_BYTES(0x8B, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(edi, cafebabe));
EXPECT_BYTES(0x8B, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// And destination modes.
asm_.mov(Operand(eax, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ecx, cafebabe), eax);
EXPECT_BYTES(0x89, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ebx, cafebabe), eax);
EXPECT_BYTES(0x89, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(edx, cafebabe), eax);
EXPECT_BYTES(0x89, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ebp, cafebabe), eax);
EXPECT_BYTES(0x89, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.mov(Operand(esp, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x24, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(esi, cafebabe), eax);
EXPECT_BYTES(0x89, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(edi, cafebabe), eax);
EXPECT_BYTES(0x89, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// Test a sampling of 8-bit displacements.
Displacement ca(0xCA, kSize8Bit, NULL);
// Source.
asm_.mov(ebx, Operand(eax, ca));
EXPECT_BYTES(0x8B, 0x58, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.mov(eax, Operand(esp, ca));
EXPECT_BYTES(0x8B, 0x44, 0x24, 0xCA);
// And destination modes.
asm_.mov(Operand(eax, ca), ebx);
EXPECT_BYTES(0x89, 0x58, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.mov(Operand(esp, ca), eax);
EXPECT_BYTES(0x89, 0x44, 0x24, 0xCA);
}
TEST_F(AssemblerTest, MovDisplacementIndirect) {
// Displacement-only mode.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
// Source, note EAX has a shortcut encoding.
asm_.mov(eax, Operand(cafebabe));
EXPECT_BYTES(0xA1, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(ecx, Operand(cafebabe));
EXPECT_BYTES(0x8B, 0x0D, 0xBE, 0xBA, 0xFE, 0xCA);
// Destination, again EAX is special.
asm_.mov(Operand(cafebabe), eax);
EXPECT_BYTES(0xA3, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(cafebabe), ecx);
EXPECT_BYTES(0x89, 0x0D, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, MovRegisterBaseDisplacementScaleIndirect) {
// There are 8 base * 7 index * 4 scales = 224 combinations.
// We don't test all of them, but rather cycle through each of base,
// index and scale individually.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
// Source mode, base register.
asm_.mov(edx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x94, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(edx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ebx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(esp, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x84, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(ebp, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(esi, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(edi, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// Source mode, index register.
asm_.mov(ebx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, ecx, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x88, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, edx, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x90, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, ebx, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, ebp, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0xA8, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, esi, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0xB0, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(eax, Operand(eax, edi, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x84, 0xB8, 0xBE, 0xBA, 0xFE, 0xCA);
// Source mode, Scale.
asm_.mov(ebx, Operand(ecx, eax, kTimes1, cafebabe));
EXPECT_BYTES(0x8B, 0x9C, 0x01, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(ebx, Operand(ecx, eax, kTimes2, cafebabe));
EXPECT_BYTES(0x8B, 0x9C, 0x41, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(ebx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8B, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(ebx, Operand(ecx, eax, kTimes8, cafebabe));
EXPECT_BYTES(0x8B, 0x9C, 0xC1, 0xBE, 0xBA, 0xFE, 0xCA);
// Destination mode, base register.
asm_.mov(Operand(eax, eax, kTimes4, cafebabe), ecx);
EXPECT_BYTES(0x89, 0x8C, 0x80, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ecx, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(edx, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ebx, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(esp, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x84, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ebp, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(esi, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(edi, eax, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// Destination mode, index register.
asm_.mov(Operand(ecx, eax, kTimes4, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, ecx, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x88, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, edx, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x90, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, ebx, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, ebp, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0xA8, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, esi, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0xB0, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(eax, edi, kTimes4, cafebabe), eax);
EXPECT_BYTES(0x89, 0x84, 0xB8, 0xBE, 0xBA, 0xFE, 0xCA);
// Destination mode, Scale.
asm_.mov(Operand(ecx, eax, kTimes1, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x9C, 0x01, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ecx, eax, kTimes2, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x9C, 0x41, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ecx, eax, kTimes4, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov(Operand(ecx, eax, kTimes8, cafebabe), ebx);
EXPECT_BYTES(0x89, 0x9C, 0xC1, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, MovRegisterBaseIndexScaleIndirect) {
// Tests the displacement-less [base + index * scale].
asm_.mov(edx, Operand(esi, eax, kTimes8));
EXPECT_BYTES(0x8B, 0x14, 0xC6);
}
TEST_F(AssemblerTest, MovRegisterDisplacementScaleIndirect) {
// Tests [index * scale + displ] modes, which are always encoded with a
// 32-bit displacement, including [index * scale], which has a zero 32-bit
// displacement that will be omitted from disassembly.
Displacement one(1, kSize8Bit, NULL);
// Source mode.
asm_.mov(edx, Operand(eax, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0x85, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(ecx, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0x8D, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(edx, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0x95, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(ebx, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0x9D, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(ebp, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0xAD, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(esi, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0xB5, 0x01, 0x00, 0x00, 0x00);
asm_.mov(edx, Operand(edi, kTimes4, one));
EXPECT_BYTES(0x8B, 0x14, 0xBD, 0x01, 0x00, 0x00, 0x00);
// Destination mode.
asm_.mov(Operand(eax, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0x85, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(ecx, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0x8D, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(edx, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0x95, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(ebx, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0x9D, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(ebp, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0xAD, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(esi, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0xB5, 0x01, 0x00, 0x00, 0x00);
asm_.mov(Operand(edi, kTimes4, one), edx);
EXPECT_BYTES(0x89, 0x14, 0xBD, 0x01, 0x00, 0x00, 0x00);
}
TEST_F(AssemblerTest, MovImmToRegisterDisplacementScaleIndirect) {
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
Immediate deadbeef(0xDEADBEEF, kSize32Bit, NULL);
// We expect the operand encoding has been adequately tested elsewhere,
// so we only test one variant here.
asm_.mov(Operand(ecx, eax, kTimes4, cafebabe), deadbeef);
EXPECT_BYTES(0xC7, 0x84, 0x81,
0xBE, 0xBA, 0xFE, 0xCA,
0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, MovWithSegmentPrefix) {
// Indirect register destination modes.
asm_.mov_fs(Operand(eax), ebx);
EXPECT_BYTES(0x64, 0x89, 0x18);
asm_.mov_fs(Operand(ecx), eax);
EXPECT_BYTES(0x64, 0x89, 0x01);
asm_.mov_fs(Operand(ebx), edx);
EXPECT_BYTES(0x64, 0x89, 0x13);
asm_.mov_fs(Operand(edx), ecx);
EXPECT_BYTES(0x64, 0x89, 0x0A);
// Indirect register only source modes.
asm_.mov_fs(ebx, Operand(eax));
EXPECT_BYTES(0x64, 0x8B, 0x18);
asm_.mov_fs(eax, Operand(ecx));
EXPECT_BYTES(0x64, 0x8B, 0x01);
asm_.mov_fs(edx, Operand(ebx));
EXPECT_BYTES(0x64, 0x8B, 0x13);
asm_.mov_fs(ecx, Operand(edx));
EXPECT_BYTES(0x64, 0x8B, 0x0A);
// Immediate source modes.
asm_.mov_fs(eax, Immediate(0xCAFEBABE, kSize32Bit));
EXPECT_BYTES(0x64, 0xA1, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.mov_fs(ebx, Immediate(0x2C, kSize8Bit));
EXPECT_BYTES(0x64, 0x8B, 0x1D, 0x2C, 0x00, 0x00, 0x00);
}
TEST_F(AssemblerTest, LeaRegisterIndirect) {
// Indirect register only source modes.
asm_.lea(ebx, Operand(eax));
EXPECT_BYTES(0x8D, 0x18);
asm_.lea(eax, Operand(ecx));
EXPECT_BYTES(0x8D, 0x01);
asm_.lea(edx, Operand(ebx));
EXPECT_BYTES(0x8D, 0x13);
asm_.lea(ecx, Operand(edx));
EXPECT_BYTES(0x8D, 0x0A);
// Note that EBP is a special case that always requires a displacement.
asm_.lea(ebx, Operand(ebp));
EXPECT_BYTES(0x8D, 0x5D, 0x00);
// Note that ESP is a special case that always requires a SIB byte.
asm_.lea(ecx, Operand(esp));
EXPECT_BYTES(0x8D, 0x0C, 0x24);
asm_.lea(ebx, Operand(esi));
EXPECT_BYTES(0x8D, 0x1E);
asm_.lea(eax, Operand(edi));
EXPECT_BYTES(0x8D, 0x07);
}
TEST_F(AssemblerTest, LeaRegisterDisplacementIndirect) {
// Register & displacement source modes.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
asm_.lea(ebx, Operand(eax, cafebabe));
EXPECT_BYTES(0x8D, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ecx, cafebabe));
EXPECT_BYTES(0x8D, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ebx, cafebabe));
EXPECT_BYTES(0x8D, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(edx, cafebabe));
EXPECT_BYTES(0x8D, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ebp, cafebabe));
EXPECT_BYTES(0x8D, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.lea(eax, Operand(esp, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x24, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(esi, cafebabe));
EXPECT_BYTES(0x8D, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(edi, cafebabe));
EXPECT_BYTES(0x8D, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// Test a sampling of 8-bit displacements.
Displacement ca(0xCA, kSize8Bit, NULL);
// Source.
asm_.lea(ebx, Operand(eax, ca));
EXPECT_BYTES(0x8D, 0x58, 0xCA);
// ESP requires a SIB byte and has a longer encoding.
asm_.lea(eax, Operand(esp, ca));
EXPECT_BYTES(0x8D, 0x44, 0x24, 0xCA);
}
TEST_F(AssemblerTest, LeaDisplacementIndirect) {
// Displacement-only mode.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
asm_.lea(eax, Operand(cafebabe));
EXPECT_BYTES(0x8D, 0x05, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(ecx, Operand(cafebabe));
EXPECT_BYTES(0x8D, 0x0D, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, LeaRegisterDisplacementScaleIndirect) {
// There are 8 base * 7 index * 4 scales = 224 combinations.
// We don't test all of them, but rather cycle through each of base,
// index and scale individually.
Displacement cafebabe(0xCAFEBABE, kSize32Bit, NULL);
// Source mode, base register.
asm_.lea(edx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x94, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(edx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x82, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ebx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x83, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(esp, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x84, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(ebp, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x85, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(esi, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x86, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(edi, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x87, 0xBE, 0xBA, 0xFE, 0xCA);
// Source mode, index register.
asm_.lea(ebx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, ecx, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x88, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, edx, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x90, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, ebx, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0x98, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, ebp, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0xA8, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, esi, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0xB0, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(eax, Operand(eax, edi, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x84, 0xB8, 0xBE, 0xBA, 0xFE, 0xCA);
// Source mode, Scale.
asm_.lea(ebx, Operand(ecx, eax, kTimes1, cafebabe));
EXPECT_BYTES(0x8D, 0x9C, 0x01, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(ebx, Operand(ecx, eax, kTimes2, cafebabe));
EXPECT_BYTES(0x8D, 0x9C, 0x41, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(ebx, Operand(ecx, eax, kTimes4, cafebabe));
EXPECT_BYTES(0x8D, 0x9C, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.lea(ebx, Operand(ecx, eax, kTimes8, cafebabe));
EXPECT_BYTES(0x8D, 0x9C, 0xC1, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, Push) {
// Register push.
asm_.push(eax);
asm_.push(ecx);
asm_.push(edx);
asm_.push(ebx);
asm_.push(esp);
asm_.push(ebp);
asm_.push(esi);
asm_.push(edi);
EXPECT_BYTES(0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57);
// Immediate push.
asm_.push(Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x68, 0xBE, 0xBA, 0xFE, 0xCA);
// General push, try one variant as the rest are OperandImpl encodings.
asm_.push(Operand(Displacement(0xCAFEBABE, kSize32Bit, NULL)));
EXPECT_BYTES(0xFF, 0x35, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.pushad();
EXPECT_BYTES(0x60);
}
TEST_F(AssemblerTest, Pop) {
// Register pop.
asm_.pop(eax);
asm_.pop(ecx);
asm_.pop(edx);
asm_.pop(ebx);
asm_.pop(esp);
asm_.pop(ebp);
asm_.pop(esi);
asm_.pop(edi);
EXPECT_BYTES(0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F);
// General pop, try one variant as the rest are OperandImpl encodings.
asm_.pop(Operand(Displacement(0xCAFEBABE, kSize32Bit, NULL)));
EXPECT_BYTES(0x8F, 0x05, 0xBE, 0xBA, 0xFE, 0xCA);
asm_.popad();
EXPECT_BYTES(0x61);
}
TEST_F(AssemblerTest, Flags) {
asm_.pushfd();
asm_.popfd();
asm_.lahf();
asm_.sahf();
EXPECT_BYTES(0x9C, 0x9D, 0x9F, 0x9E);
}
TEST_F(AssemblerTest, TestByte) {
asm_.test(al, bl);
EXPECT_BYTES(0x84, 0xC3);
asm_.test(bh, al);
EXPECT_BYTES(0x84, 0xF8);
asm_.test(al, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0xA8, 0x0A);
asm_.test(bh, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0xF6, 0xC7, 0x0A);
}
TEST_F(AssemblerTest, Test) {
asm_.test(eax, ecx);
EXPECT_BYTES(0x85, 0xC1);
asm_.test(ecx, Operand(eax));
EXPECT_BYTES(0x85, 0x08);
asm_.test(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x85, 0x48, 0x0A);
asm_.test(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x85, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.test(ecx, eax);
EXPECT_BYTES(0x85, 0xC8);
asm_.test(ecx, Operand(eax));
EXPECT_BYTES(0x85, 0x08);
asm_.test(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x85, 0x48, 0x0A);
asm_.test(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x85, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.test(Operand(eax), ecx);
EXPECT_BYTES(0x85, 0x08);
asm_.test(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x85, 0x48, 0x0A);
asm_.test(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x85, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.test(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0xA9, 0x0A, 0x00, 0x00, 0x00);
asm_.test(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0xF7, 0xC1, 0x0A, 0x00, 0x00, 0x00);
asm_.test(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0xF7, 0xC1, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.test(Operand(eax), Immediate(1, kSize8Bit));
EXPECT_BYTES(0xF7, 0x00, 0x01, 0x00, 0x00, 0x00);
asm_.test(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0xF7, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.test(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0xF7, 0x40, 0x0A, 0x01, 0x00, 0x00, 0x00);
asm_.test(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0xF7, 0x40, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.test(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0xF7, 0x80, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.test(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0xA9, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, CmpByte) {
asm_.cmp(al, bl);
EXPECT_BYTES(0x3A, 0xC3);
asm_.cmp(bh, al);
EXPECT_BYTES(0x3A, 0xF8);
asm_.cmp(al, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x3C, 0x0A);
asm_.cmp(bh, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x80, 0xFF, 0x0A);
}
TEST_F(AssemblerTest, Cmp) {
asm_.cmp(eax, ecx);
EXPECT_BYTES(0x3B, 0xC1);
asm_.cmp(ecx, Operand(eax));
EXPECT_BYTES(0x3B, 0x08);
asm_.cmp(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x3B, 0x48, 0x0A);
asm_.cmp(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x3B, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.cmp(ecx, eax);
EXPECT_BYTES(0x3B, 0xC8);
asm_.cmp(ecx, Operand(eax));
EXPECT_BYTES(0x3B, 0x08);
asm_.cmp(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x3B, 0x48, 0x0A);
asm_.cmp(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x3B, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.cmp(Operand(eax), ecx);
EXPECT_BYTES(0x39, 0x08);
asm_.cmp(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x39, 0x48, 0x0A);
asm_.cmp(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x39, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.cmp(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xF8, 0x0A);
asm_.cmp(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xF9, 0x0A);
asm_.cmp(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xF9, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.cmp(Operand(eax), Immediate(1, kSize8Bit));
EXPECT_BYTES(0x83, 0x38, 0x01);
asm_.cmp(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x38, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.cmp(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0x83, 0x78, 0x0A, 0x1);
asm_.cmp(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x78, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.cmp(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xB8, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.cmp(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x3D, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, IncByte) {
asm_.inc(Operand(eax));
EXPECT_BYTES(0xFE, 0x00);
asm_.inc(Operand(ecx));
EXPECT_BYTES(0xFE, 0x01);
asm_.inc(Operand(edx));
EXPECT_BYTES(0xFE, 0x02);
asm_.inc(Operand(ebx));
EXPECT_BYTES(0xFE, 0x03);
asm_.inc(Operand(esi));
EXPECT_BYTES(0xFE, 0x06);
asm_.inc(Operand(edi));
EXPECT_BYTES(0xFE, 0x07);
asm_.inc(Operand(ebp));
EXPECT_BYTES(0xFE, 0x45, 0x00);
asm_.inc(Operand(esp));
EXPECT_BYTES(0xFE, 0x04, 0x24);
}
TEST_F(AssemblerTest, AddByte) {
asm_.add(al, bl);
EXPECT_BYTES(0x02, 0xC3);
asm_.add(bh, al);
EXPECT_BYTES(0x02, 0xF8);
asm_.add(al, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x04, 0x0A);
asm_.add(bh, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x80, 0xC7, 0x0A);
}
TEST_F(AssemblerTest, Add) {
asm_.add(eax, eax);
EXPECT_BYTES(0x03, 0xC0);
asm_.add(eax, Operand(eax));
EXPECT_BYTES(0x03, 0x00);
asm_.add(eax, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x03, 0x40, 0x0A);
asm_.add(eax, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x03, 0x80, 0x0A, 0x00, 0x00, 0x00);
asm_.add(ecx, eax);
EXPECT_BYTES(0x03, 0xC8);
asm_.add(ecx, Operand(eax));
EXPECT_BYTES(0x03, 0x08);
asm_.add(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x03, 0x48, 0x0A);
asm_.add(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x03, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.add(eax, ecx);
EXPECT_BYTES(0x03, 0xC1);
asm_.add(Operand(eax), ecx);
EXPECT_BYTES(0x01, 0x08);
asm_.add(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x01, 0x48, 0x0A);
asm_.add(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x01, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.add(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xC0, 0x0A);
asm_.add(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xC1, 0x0A);
asm_.add(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xC1, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.add(Operand(eax), Immediate(1, kSize8Bit));
EXPECT_BYTES(0x83, 0x00, 0x01);
asm_.add(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.add(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x40, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.add(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x80, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.add(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x05, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, SubByte) {
asm_.sub(al, bl);
EXPECT_BYTES(0x2A, 0xC3);
asm_.sub(bh, al);
EXPECT_BYTES(0x2A, 0xF8);
asm_.sub(al, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x2C, 0x0A);
asm_.sub(bh, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x80, 0xEF, 0x0A);
}
TEST_F(AssemblerTest, Sub) {
asm_.sub(eax, eax);
EXPECT_BYTES(0x2B, 0xC0);
asm_.sub(eax, Operand(eax));
EXPECT_BYTES(0x2B, 0x00);
asm_.sub(eax, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x2B, 0x40, 0x0A);
asm_.sub(eax, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x2B, 0x80, 0x0A, 0x00, 0x00, 0x00);
asm_.sub(ecx, eax);
EXPECT_BYTES(0x2B, 0xC8);
asm_.sub(ecx, Operand(eax));
EXPECT_BYTES(0x2B, 0x08);
asm_.sub(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x2B, 0x48, 0x0A);
asm_.sub(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x2B, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.sub(eax, ecx);
EXPECT_BYTES(0x2B, 0xC1);
asm_.sub(Operand(eax), ecx);
EXPECT_BYTES(0x29, 0x08);
asm_.sub(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x29, 0x48, 0x0A);
asm_.sub(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x29, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.sub(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xE8, 0x0A);
asm_.sub(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xE9, 0x0A);
asm_.sub(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xE9, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.sub(Operand(eax), Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0x83, 0x28, 0x01);
asm_.sub(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x28, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.sub(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x68, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.sub(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xA8, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.sub(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x2D, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, Imul) {
asm_.imul(ecx, eax);
EXPECT_BYTES(0x0F, 0xAF, 0xC8);
asm_.imul(ecx, Operand(eax));
EXPECT_BYTES(0x0F, 0xAF, 0x08);
asm_.imul(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x0F, 0xAF, 0x48, 0x0A);
asm_.imul(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x0F, 0xAF, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.imul(ecx, eax, Immediate(0xABABABAB, kSize32Bit));
EXPECT_BYTES(0x69, 0xC8, 0xAB, 0xAB, 0xAB, 0xAB);
}
TEST_F(AssemblerTest, And) {
asm_.and(eax, eax);
EXPECT_BYTES(0x21, 0xC0);
asm_.and(eax, Operand(eax));
EXPECT_BYTES(0x23, 0x00);
asm_.and(eax, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x23, 0x40, 0x0A);
asm_.and(eax, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x23, 0x80, 0x0A, 0x00, 0x00, 0x00);
asm_.and(ecx, eax);
EXPECT_BYTES(0x21, 0xC1);
asm_.and(ecx, Operand(eax));
EXPECT_BYTES(0x23, 0x08);
asm_.and(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x23, 0x48, 0x0A);
asm_.and(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x23, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.and(eax, ecx);
EXPECT_BYTES(0x21, 0xC8);
asm_.and(Operand(eax), ecx);
EXPECT_BYTES(0x21, 0x08);
asm_.and(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x21, 0x48, 0x0A);
asm_.and(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x21, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.and(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xE0, 0x0A);
asm_.and(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xE1, 0x0A);
asm_.and(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xE1, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.and(Operand(eax), Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0x83, 0x20, 0x01);
asm_.and(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x20, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.and(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x60, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.and(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xA0, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.and(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x25, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, Xor) {
asm_.xor(eax, eax);
EXPECT_BYTES(0x31, 0xC0);
asm_.xor(eax, Operand(eax));
EXPECT_BYTES(0x33, 0x00);
asm_.xor(eax, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x33, 0x40, 0x0A);
asm_.xor(eax, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x33, 0x80, 0x0A, 0x00, 0x00, 0x00);
asm_.xor(ecx, eax);
EXPECT_BYTES(0x31, 0xC1);
asm_.xor(ecx, Operand(eax));
EXPECT_BYTES(0x33, 0x08);
asm_.xor(ecx, Operand(eax, Displacement(10, kSize8Bit)));
EXPECT_BYTES(0x33, 0x48, 0x0A);
asm_.xor(ecx, Operand(eax, Displacement(10, kSize32Bit)));
EXPECT_BYTES(0x33, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.xor(eax, ecx);
EXPECT_BYTES(0x31, 0xC8);
asm_.xor(Operand(eax), ecx);
EXPECT_BYTES(0x31, 0x08);
asm_.xor(Operand(eax, Displacement(10, kSize8Bit)), ecx);
EXPECT_BYTES(0x31, 0x48, 0x0A);
asm_.xor(Operand(eax, Displacement(10, kSize32Bit)), ecx);
EXPECT_BYTES(0x31, 0x88, 0x0A, 0x00, 0x00, 0x00);
asm_.xor(eax, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xF0, 0x0A);
asm_.xor(ecx, Immediate(0x0A, kSize8Bit));
EXPECT_BYTES(0x83, 0xF1, 0x0A);
asm_.xor(ecx, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xF1, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.xor(Operand(eax), Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0x83, 0x30, 0x01);
asm_.xor(Operand(eax), Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x30, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.xor(Operand(eax, Displacement(10, kSize8Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0x70, 0x0A, 0xEF, 0xBE, 0xAD, 0xDE);
asm_.xor(Operand(eax, Displacement(10, kSize32Bit)),
Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x81, 0xB0, 0x0A, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE);
// Special EAX mode + immediate.
asm_.xor(eax, Immediate(0xDEADBEEF, kSize32Bit));
EXPECT_BYTES(0x35, 0xEF, 0xBE, 0xAD, 0xDE);
}
TEST_F(AssemblerTest, Shl) {
asm_.shl(eax, Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0xD1, 0xE0);
asm_.shl(eax, Immediate(0x3, kSize8Bit));
EXPECT_BYTES(0xC1, 0xE0, 0x03);
asm_.shl(ecx, Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0xD1, 0xE1);
asm_.shl(ecx, Immediate(0x3, kSize8Bit));
EXPECT_BYTES(0xC1, 0xE1, 0x03);
}
TEST_F(AssemblerTest, Shr) {
asm_.shr(eax, Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0xD1, 0xE8);
asm_.shr(eax, Immediate(0x3, kSize8Bit));
EXPECT_BYTES(0xC1, 0xE8, 0x03);
asm_.shr(ecx, Immediate(0x1, kSize8Bit));
EXPECT_BYTES(0xD1, 0xE9);
asm_.shr(ecx, Immediate(0x3, kSize8Bit));
EXPECT_BYTES(0xC1, 0xE9, 0x03);
}
TEST_F(AssemblerTest, Xchg32) {
// Any exchange with the eax register should generate a single byte
// instruction.
asm_.xchg(eax, eax);
EXPECT_BYTES(0x90);
asm_.xchg(eax, ecx);
EXPECT_BYTES(0x91);
asm_.xchg(esp, eax);
EXPECT_BYTES(0x94);
// Any exchanges not involving the eax register should generate 2-byte
// instructions.
asm_.xchg(ebx, ecx);
EXPECT_BYTES(0x87, 0xCB);
asm_.xchg(edx, esp);
EXPECT_BYTES(0x87, 0xE2);
asm_.xchg(esp, edx);
EXPECT_BYTES(0x87, 0xD4);
int ref = 0;
asm_.xchg(eax,
Operand(ecx, Displacement(0xCAFEBABE, kSize32Bit, &ref)));
EXPECT_BYTES(0x87, 0x81, 0xBE, 0xBA, 0xFE, 0xCA);
}
TEST_F(AssemblerTest, Xchg16) {
// Any exchange with the ax register should generate 2-byte instructions.
asm_.xchg(ax, ax);
EXPECT_BYTES(0x66, 0x90);
asm_.xchg(ax, cx);
EXPECT_BYTES(0x66, 0x91);
asm_.xchg(sp, ax);
EXPECT_BYTES(0x66, 0x94);
// Any exchanges not involving the ax register should generate 3-byte
// instructions.
asm_.xchg(cx, dx);
EXPECT_BYTES(0x66, 0x87, 0xD1);
asm_.xchg(bx, cx);
EXPECT_BYTES(0x66, 0x87, 0xCB);
asm_.xchg(dx, sp);
EXPECT_BYTES(0x66, 0x87, 0xE2);
asm_.xchg(sp, dx);
EXPECT_BYTES(0x66, 0x87, 0xD4);
asm_.xchg(bp, dx);
EXPECT_BYTES(0x66, 0x87, 0xD5);
asm_.xchg(si, sp);
EXPECT_BYTES(0x66, 0x87, 0xE6);
asm_.xchg(di, cx);
EXPECT_BYTES(0x66, 0x87, 0xCF);
}
TEST_F(AssemblerTest, Xchg8) {
asm_.xchg(al, ah);
EXPECT_BYTES(0x86, 0xE0);
asm_.xchg(cl, bl);
EXPECT_BYTES(0x86, 0xD9);
asm_.xchg(dl, bh);
EXPECT_BYTES(0x86, 0xFA);
asm_.xchg(bl, dh);
EXPECT_BYTES(0x86, 0xF3);
asm_.xchg(ah, cl);
EXPECT_BYTES(0x86, 0xCC);
asm_.xchg(ch, dl);
EXPECT_BYTES(0x86, 0xD5);
asm_.xchg(dh, ch);
EXPECT_BYTES(0x86, 0xEE);
asm_.xchg(bh, al);
EXPECT_BYTES(0x86, 0xC7);
}
TEST_F(AssemblerTest, Ja) {
ConditionCode cc = kAbove;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x77, 0xFE);
ASSERT_EQ(1, kShortBranchOpcodeSize);
ASSERT_EQ(2, kShortBranchSize);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x87, 0xF8, 0xFF, 0xFF, 0xFF);
ASSERT_EQ(2, kLongBranchOpcodeSize);
ASSERT_EQ(6, kLongBranchSize);
}
TEST_F(AssemblerTest, Jae) {
ConditionCode cc = kAboveEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x73, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x83, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jb) {
ConditionCode cc = kBelow;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x72, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x82, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jbe) {
ConditionCode cc = kBelowEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x76, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x86, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jc) {
ConditionCode cc = kCarry;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x72, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x82, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Je) {
ConditionCode cc = kEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x74, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x84, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jecxz) {
asm_.set_location(0xCAFEBABE);
asm_.jecxz(Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0xE3, 0xFE);
}
TEST_F(AssemblerTest, Jg) {
ConditionCode cc = kGreater;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7F, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8F, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jge) {
ConditionCode cc = kGreaterEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7D, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8D, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jl) {
ConditionCode cc = kLess;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7C, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8C, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jle) {
ConditionCode cc = kLessEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7E, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8E, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jo) {
ConditionCode cc = kOverflow;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x70, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x80, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jpe) {
ConditionCode cc = kParityEven;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7A, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8A, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jpo) {
ConditionCode cc = kParityOdd;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x7B, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x8B, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Js) {
ConditionCode cc = kSign;
asm_.set_location(0xCAFEBABE);
static_assert(kSign == kNegative, "Sign and Positive are aliases.");
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x78, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x88, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jz) {
ConditionCode cc = kZero;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x74, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x84, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jnc) {
ConditionCode cc = kNotCarry;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x73, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x83, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jne) {
ConditionCode cc = kNotEqual;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x75, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x85, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jno) {
ConditionCode cc = kNoOverflow;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x71, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x81, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jns) {
static_assert(kNotSign == kPositive, "Sign and positive are aliases.");
ConditionCode cc = kNotSign;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x79, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x89, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, Jnz) {
ConditionCode cc = kNotZero;
asm_.set_location(0xCAFEBABE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0x75, 0xFE);
asm_.j(cc, Immediate(0xCAFEBABE, kSize32Bit, NULL));
EXPECT_BYTES(0x0F, 0x85, 0xF8, 0xFF, 0xFF, 0xFF);
}
TEST_F(AssemblerTest, JnzToBoundLabel) {
ConditionCode cc = kNotZero;
asm_.set_location(0xCAFEBABE);
// Bind the label.
Label label(&asm_);
label.Bind();
// Test default to short.
EXPECT_TRUE(asm_.j(cc, &label));
// Test explicit long.
EXPECT_TRUE(asm_.j(cc, &label, kSize32Bit));
EXPECT_BYTES(0x75, 0xFE,
0x0F, 0x85, 0xF8, 0xFF, 0xFF, 0xFF);
// Jump the location to the limit of the negative 8 bit range of -128 bytes
// from the start of the succeeding instruction.
asm_.set_location(0xCAFEBABE + 128 - kShortBranchSize);
EXPECT_TRUE(asm_.j(cc, &label));
EXPECT_BYTES(0x75, 0x80);
// Jump the location just beyond the negative 8 bit range of -128 bytes
// from the start of the succeeding instruction.
asm_.set_location(0xCAFEBABE + 128 - kShortBranchSize + 1);
EXPECT_TRUE(asm_.j(cc, &label));
EXPECT_BYTES(0x0F, 0x85, 0x7B, 0xFF, 0xFF, 0xFF);
// Jump the location to the limit of the positive 8 bit range of +127 bytes
// from the start of the succeeding instruction.
asm_.set_location(0xCAFEBABE - (127 + kShortBranchSize));
EXPECT_TRUE(asm_.j(cc, &label));
EXPECT_BYTES(0x75, 0x7F);
// Jump the location just beyond the positive 8 bit range of +127 bytes
// from the start of the succeeding instruction.
asm_.set_location(0xCAFEBABE - (127 + kShortBranchSize + 1));
// Test that requesting a short reach fails.
EXPECT_FALSE(asm_.j(cc, &label, kSize8Bit));
// Test default generation of long reach.
EXPECT_TRUE(asm_.j(cc, &label));
EXPECT_BYTES(0x0F, 0x85, 0x7C, 0x00, 0x00, 0x00);
}
TEST_F(AssemblerTest, JnzToUnBoundLabel) {
ConditionCode cc = kNotZero;
asm_.set_location(0xCAFEBABE);
// Create a label.
Label label(&asm_);
// The default is a long jump.
EXPECT_TRUE(asm_.j(cc, &label));
// Generate an explicit long jump.
EXPECT_TRUE(asm_.j(cc, &label, kSize32Bit));
// Generate a short jump also.
EXPECT_TRUE(asm_.j(cc, &label, kSize8Bit));
EXPECT_TRUE(label.Bind());
EXPECT_BYTES(0x0F, 0x85, 0x08, 0x00, 0x00, 0x00,
0x0F, 0x85, 0x02, 0x00, 0x00, 0x00,
0x75, 0x00);
}
TEST_F(AssemblerTest, JnzToOutOfBoundsLabel) {
ConditionCode cc = kNotZero;
asm_.set_location(0xCAFEBABE);
// Create a label.
Label label(&asm_);
// Generate a short jump.
asm_.j(cc, &label, kSize8Bit);
// Move the location forward past the range of an 8 bit PC-relative ref.
asm_.set_location(asm_.location() + 128);
EXPECT_FALSE(label.Bind());
}
TEST_F(AssemblerTest, Seto) {
asm_.set_location(0xCAFEBABE);
asm_.set(kOverflow, eax);
EXPECT_BYTES(0x0F, 0x90, 0xC0);
}
TEST_F(AssemblerTest, Setno) {
asm_.set(kNoOverflow, ebx);
EXPECT_BYTES(0x0F, 0x91, 0xC3);
}
TEST_F(AssemblerTest, Sete) {
asm_.set(kEqual, eax);
EXPECT_BYTES(0x0F, 0x94, 0xC0);
}
TEST_F(AssemblerTest, Setne) {
asm_.set(kNotEqual, eax);
EXPECT_BYTES(0x0F, 0x95, 0xC0);
}
TEST_F(AssemblerTest, Setb) {
asm_.set(kBelow, eax);
EXPECT_BYTES(0x0F, 0x92, 0xC0);
}
TEST_F(AssemblerTest, Loop) {
asm_.set_location(0xCAFEBABE);
asm_.loop(Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0xE2, 0xFE);
}
TEST_F(AssemblerTest, Loope) {
asm_.set_location(0xCAFEBABE);
asm_.loope(Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0xE1, 0xFE);
}
TEST_F(AssemblerTest, Loopne) {
asm_.set_location(0xCAFEBABE);
asm_.loopne(Immediate(0xCAFEBABE, kSize8Bit, NULL));
EXPECT_BYTES(0xE0, 0xFE);
}
TEST_F(AssemblerTest, References) {
// We arbitrarily use the MOV instruction to test reference propagation.
static const int ref1 = 1;
asm_.mov(eax, Immediate(0, kSize8Bit, &ref1));
static const int ref2 = 2;
asm_.mov(eax, Operand(eax, ebx, kTimes4,
Displacement(0, kSize32Bit, &ref2)));
static const int ref3 = 3;
static const int ref4 = 4;
asm_.mov(Operand(eax, ebx, kTimes4, Displacement(0, kSize32Bit, &ref3)),
Immediate(0, kSize32Bit, &ref4));
EXPECT_EQ(4, serializer_.references.size());
EXPECT_EQ(1, serializer_.references[0].location);
EXPECT_EQ(&ref1, serializer_.references[0].ref);
EXPECT_EQ(8, serializer_.references[1].location);
EXPECT_EQ(&ref2, serializer_.references[1].ref);
EXPECT_EQ(15, serializer_.references[2].location);
EXPECT_EQ(&ref3, serializer_.references[2].ref);
EXPECT_EQ(19, serializer_.references[3].location);
EXPECT_EQ(&ref4, serializer_.references[3].ref);
}
} // namespace assm