/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.assembler.x86;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream;
import org.jnode.assembler.ObjectResolver;
import org.jnode.assembler.UnresolvedObjectRefException;
import org.jnode.assembler.x86.X86Register.CRX;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.assembler.x86.X86Register.GPR32;
import org.jnode.assembler.x86.X86Register.GPR64;
import org.jnode.assembler.x86.X86Register.MMX;
import org.jnode.assembler.x86.X86Register.SR;
import org.jnode.assembler.x86.X86Register.XMM;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.VmClassType;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.x86.X86CpuID;
import static org.jnode.assembler.x86.X86Register.CS;
import static org.jnode.assembler.x86.X86Register.DS;
import static org.jnode.assembler.x86.X86Register.ES;
import static org.jnode.assembler.x86.X86Register.FS;
import static org.jnode.assembler.x86.X86Register.GS;
import static org.jnode.assembler.x86.X86Register.SS;
/**
* Implementation of AbstractX86Stream.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
* @author Levente S\u00e1ntha (lsantha@users.sourceforge.net)
* @author Patrik Reali (patrik_reali@users.sourceforge.net)
*/
public class X86BinaryAssembler extends X86Assembler implements X86Operation {
static final class Key {
private final Object key;
public Key(Object key) {
this.key = key;
}
/**
* Test if this Key is equal to the supplied object. The semantics
* of equality depend on what the 'key' is. If it is a {@link Label}, then two
* Keys are equal if the Label values are equal. Otherwise, two keys are equal if
* the 'key' values refer to the same object.
*
* @param obj the object to test for equality.
* @return Return {@code true} if obj is 'equal to' this, {@code false} otherwise.
*/
public final boolean equals(Object obj) {
if (obj == null || !(obj instanceof Key)) {
return false;
}
obj = ((Key) obj).key;
if (this.key instanceof Label) {
return key.equals(obj);
} else {
return (obj == this.key);
}
}
/**
* The hashcode is the hashcode for the Key's 'key' object.
*
* @return This Key instance's hashcode.
*/
public final int hashCode() {
return key.hashCode();
}
}
public class X86ObjectInfo extends NativeStream.ObjectInfo {
private int m_objptr;
X86ObjectInfo() {
m_objptr = getLength();
}
/**
* Mark the current location as the end of this object end fixup the
* objectheader.
*/
public void markEnd() {
if (!inObject) {
throw new RuntimeException("inObject == false");
}
if (m_objptr == -1) {
throw new RuntimeException("markEnd has already been called");
}
align(ObjectLayout.OBJECT_ALIGN);
final int size = getLength() - m_objptr;
if (isCode32()) {
set32(m_objptr - (3 * 4), size);
} else {
set64(m_objptr - (3 * 8), size);
}
m_objptr = -1;
inObject = false;
}
}
public static final class UnresolvedOffset {
private final int offset;
private final int patchSize;
public UnresolvedOffset(int offset, int patchSize) {
if ((patchSize != 1) && (patchSize != 4) && (patchSize != 8)) {
throw new IllegalArgumentException("PatchSize: " + patchSize);
}
this.offset = offset;
this.patchSize = patchSize;
}
public final int getOffset() {
return offset;
}
public final int getPatchSize() {
return patchSize;
}
}
/**
* Represents an reference to an object/label.
* The reference does not (yet) have to be resolved.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
public class X86ObjectRef extends NativeStream.ObjectRef {
private int dataOffset;
private boolean isPublic;
private boolean isRelJump;
private LinkedList<UnresolvedOffset> unresolvedLinks; // Array of data_offsets where
public X86ObjectRef(Object object) {
super(object);
this.dataOffset = -1;
this.unresolvedLinks = null;
this.isPublic = false;
this.isRelJump = false;
}
public void addUnresolvedLink(int offset, int patchSize) {
if (unresolvedLinks == null) {
unresolvedLinks = new LinkedList<UnresolvedOffset>();
}
unresolvedLinks.add(new UnresolvedOffset(offset, patchSize));
}
/**
* Gets the offset of the represented object/label in the
* native stream.
*
* @see org.jnode.assembler.NativeStream.ObjectRef#getOffset()
*/
public int getOffset() throws UnresolvedObjectRefException {
if (!isResolved()) {
throw new UnresolvedObjectRefException("Unresolved object: "
+ this);
}
return dataOffset;
}
public int[] getUnresolvedOffsets() {
final int cnt = unresolvedLinks.size();
final int[] offsets = new int[cnt];
int ofs = 0;
for (UnresolvedOffset unrOfs : unresolvedLinks) {
offsets[ofs++] = unrOfs.getOffset();
}
return offsets;
}
public boolean isPublic() {
return isPublic;
}
public boolean isRelJump() {
return isRelJump;
}
public boolean isResolved() {
return (dataOffset != -1);
}
/**
* Link this objectref to the given objectref. That is, the offset of
* this objectref will be set to the offset of the given objectref.
*
* @param objectRef
* @throws UnresolvedObjectRefException The given objectref is not resolved.
*/
public void link(ObjectRef objectRef)
throws UnresolvedObjectRefException {
if (!objectRef.isResolved()) {
throw new UnresolvedObjectRefException(objectRef.getObject()
.toString());
}
setOffset(objectRef.getOffset());
}
/**
* Set the startoffset of referenced object/label and resolve
* all unresolved references to it.
*
* @param offset
*/
public void setOffset(int offset) {
if (this.dataOffset != -1) {
if (getObject().toString().isEmpty()) {
return;
}
throw new RuntimeException(
"Offset is already set. Duplicate labels? ("
+ getObject() + ')');
}
if (offset < 0) {
throw new IllegalArgumentException("Offset: " + offset);
}
this.dataOffset = offset;
if (unresolvedLinks != null) {
// Link all unresolved links
for (UnresolvedOffset unrOfs : unresolvedLinks) {
final int addr = unrOfs.getOffset();
switch (unrOfs.getPatchSize()) {
case 1:
resolve8(addr, offset);
break;
case 4:
resolve32(addr, offset);
break;
case 8:
resolve64(addr, offset);
break;
default:
throw new IllegalArgumentException("Unknown patch size " + unrOfs.getPatchSize());
}
}
unresolvedLinks = null;
}
}
/**
* Resolve a 8-bit patch location.
*
* @param addr
* @param offset
*/
private final void resolve8(int addr, int offset) {
// System.out.println("addr " + addr);
// System.out.println("get8(addr) " + get8(addr));
// System.out.println("offset " + offset);
final int distance = offset - addr - 1; //get8(addr);
if (!X86Utils.isByte(distance)) {
throw new IllegalArgumentException("Jump out of byte-range (" + distance + ')');
}
if (isRelJump() && (distance == 0) && isRelJumpEnabled()) {
// JMP
if (get8(addr - 1) == 0xe9) {
set8(addr - 1, 0x90); // NOP
set8(addr, 0x90); // 1 NOP (overrides jmp offset)
} else if (get8(addr - 2) == 0x0f) {
// Jcc
set8(addr - 2, 0x90);
set8(addr - 1, 0x90);
set8(addr, 0x90); // 1 NOP
} else {
set8(addr, distance);
}
} else {
set8(addr, distance);
}
}
/**
* Resolve a 32-bit patch location.
*
* @param addr
* @param offset
*/
private final void resolve32(int addr, int offset) {
final int distance = offset - get32(addr);
if (isRelJump() && (distance == 0) && isRelJumpEnabled()) {
// JMP
if (get8(addr - 1) == 0xe9) {
set8(addr - 1, 0x90); // NOP
set32(addr, 0x90909090); // 4 NOP's
} else if (get8(addr - 2) == 0x0f) {
// Jcc
set8(addr - 2, 0x90);
set8(addr - 1, 0x90);
set32(addr, 0x90909090); // 4 NOP's
} else {
set32(addr, distance);
}
} else {
set32(addr, distance);
}
}
/**
* Resolve a 32-bit patch location.
*
* @param addr
* @param offset
*/
private final void resolve64(int addr, int offset) {
final long distance = offset - get64(addr);
if (isRelJump()) {
throw new IllegalArgumentException(
"RelJump not supported for 64-bit");
} else {
set64(addr, distance);
}
}
public void setPublic() {
isPublic = true;
}
public void setRelJump() {
isRelJump = true;
}
}
private final int baseAddr;
private int dataLength;
private int growCount;
private final int growSize;
private final boolean haveCMOV;
private final int initialObjectRefsCapacity;
boolean inObject;
private byte[] m_data;
private int m_used;
private Map<Key, X86ObjectRef> objectRefs; // Integer(labelnr),Integer(offset)
private ObjectResolver resolver;
private boolean byteValueEnabled = true;
private boolean isRelJumpEnabled = true;
/**
* Initialize this instance.
*
* @param cpuId
* @param mode
* @param baseAddr
*/
public X86BinaryAssembler(X86CpuID cpuId, Mode mode, int baseAddr) {
this(cpuId, mode, baseAddr, 1024, 128, 1024);
}
/**
* Initialize this instance.
*
* @param cpuId
* @param mode
* @param baseAddr
* @param initialObjectRefsCapacity
* @param initialSize
* @param growSize
*/
public X86BinaryAssembler(X86CpuID cpuId, Mode mode, int baseAddr,
int initialObjectRefsCapacity, int initialSize, int growSize) {
super(cpuId, mode);
this.m_data = new byte[initialSize];
this.m_used = 0;
this.baseAddr = baseAddr;
this.inObject = false;
this.initialObjectRefsCapacity = initialObjectRefsCapacity;
this.growSize = growSize;
this.haveCMOV = cpuId.hasFeature(X86CpuID.FEAT_CMOV);
}
/**
* Align on a given value
*
* @param value
* @return The number of bytes needed to align.
*/
public final int align(int value) {
int count = 0;
while ((getLength() % value) != 0) {
write8(0x90); // Nop
count++;
}
return count;
}
/**
* Remove all data and references.
*/
public final void clear() {
//this.m_data = new byte[0];
this.m_used = 0;
this.objectRefs.clear();
}
/*
// a possible growth strategy
private final void ensureSize(int extra) {
if (m_used + extra >= dataLength) {
int newLen;
byte[] newArr;
if (growSize > dataLength) {
newLen = growSize;
} else {
newLen = (dataLength << 1) + 3;
}
if (extra + dataLength > newLen) {
newLen = dataLength + extra;
}
newArr = new byte[newLen];
System.arraycopy(m_data, 0, newArr, 0, m_used);
m_data = newArr;
dataLength = newLen;
growCount++;
//System.out.println("Growing stream buffer to " + newLen);
}
}
*/
private final void ensureSize(int extra) {
if (m_used + extra >= dataLength) {
int newLen;
byte[] newArr;
if (extra > growSize) {
newLen = dataLength + extra;
} else {
newLen = dataLength + growSize;
}
newArr = new byte[newLen];
System.arraycopy(m_data, 0, newArr, 0, m_used);
m_data = newArr;
dataLength = newLen;
growCount++;
// System.out.println("Growing stream buffer to " + newLen);
}
}
/**
* Allocate space and return the offset of the start of the allocated space.
*
* @see org.jnode.assembler.BootImageNativeStream#allocate(int)
*/
public final int allocate(int size) {
ensureSize(size);
final int start = m_used;
m_used += size;
return start;
}
public final int get32(int offset) {
int v1 = m_data[offset++];
int v2 = m_data[offset++];
int v3 = m_data[offset++];
int v4 = m_data[offset];
return (v1 & 0xFF) | ((v2 & 0xFF) << 8) | ((v3 & 0xFF) << 16)
| ((v4 & 0xFF) << 24);
}
public final long get64(int offset) {
long v1 = m_data[offset++];
long v2 = m_data[offset++];
long v3 = m_data[offset++];
long v4 = m_data[offset++];
long v5 = m_data[offset++];
long v6 = m_data[offset++];
long v7 = m_data[offset++];
long v8 = m_data[offset];
return (v1 & 0xFF) | ((v2 & 0xFF) << 8) | ((v3 & 0xFF) << 16)
| ((v4 & 0xFF) << 24) | ((v5 & 0xFF) << 32)
| ((v6 & 0xFF) << 40) | ((v7 & 0xFF) << 48)
| ((v8 & 0xFF) << 56);
}
public final int get8(int offset) {
return (m_data[offset] & 0xFF);
}
/**
* Returns the base address.
*
* @return long
*/
public final long getBaseAddr() {
return baseAddr;
}
/**
* Return the actual bytes. This array may be longer then getLength() *
*
* @return The actual bytes
*/
public final byte[] getBytes() {
return m_data;
}
/**
* Get the length in bytes of valid data
*
* @return the length of valid data
*/
public final int getLength() {
return m_used;
}
/**
* Gets an objectref for a given object.
*
* @param keyObj
* @return ObjectRef
*/
public final ObjectRef getObjectRef(Object keyObj) {
if (keyObj == null) {
throw new NullPointerException("Key cannot be null");
}
if (objectRefs == null) {
objectRefs = new HashMap<Key, X86ObjectRef>(initialObjectRefsCapacity);
}
Key key = new Key(keyObj);
X86ObjectRef ref = objectRefs.get(key);
if (ref != null) {
return ref;
}
ref = new X86ObjectRef(keyObj);
objectRefs.put(key, ref);
return ref;
}
/**
* Gets all references of objects as instanceof ObjectRef
*
* @return Collection
*/
public final Collection<X86ObjectRef> getObjectRefs() {
if (objectRefs == null) {
objectRefs = new HashMap<Key, X86ObjectRef>(initialObjectRefsCapacity);
}
return objectRefs.values();
}
/**
* Gets the number of all references of objects.
*
* @return Collection
*/
public final int getObjectRefsCount() {
if (objectRefs != null) {
return objectRefs.size();
} else {
return 0;
}
}
/**
* @return ObjectResolver
*/
public final ObjectResolver getResolver() {
return resolver;
}
/**
* Gets all unresolved references of objects as instanceof ObjectRef
*
* @return Collection
*/
public final Collection<ObjectRef> getUnresolvedObjectRefs() {
final Collection<X86ObjectRef> coll = getObjectRefs();
final LinkedList<ObjectRef> result = new LinkedList<ObjectRef>();
for (X86ObjectRef ref : coll) {
if (!ref.isResolved()) {
if (!(ref.getObject() instanceof Label)) {
result.add(ref);
}
}
}
System.out.println("getUnresolvedObjectsRefs: count=" + result.size());
return result;
}
/**
* Are there unresolved references?
*
* @return True if there are unresolved references, false otherwise
*/
public final boolean hasUnresolvedObjectRefs() {
final Collection<X86ObjectRef> coll = getObjectRefs();
for (ObjectRef ref : coll) {
if (!ref.isResolved()) {
if (!(ref.getObject() instanceof Label)) {
return true;
}
}
}
return false;
}
/**
* Is logging enabled. This method will only return true on on debug like
* implementations.
*
* @return boolean
*/
public boolean isLogEnabled() {
return false;
}
/**
* @see org.jnode.assembler.x86.X86Assembler#isTextStream()
*/
public boolean isTextStream() {
return false;
}
/**
* Write a log message. This method is only implemented on debug like
* implementations.
*
* @param msg
*/
public void log(Object msg) {
// Do nothing
}
public final void set16(int offset, int v16) {
m_data[offset++] = (byte) (v16 & 0xFF);
m_data[offset++] = (byte) ((v16 >> 8) & 0xFF);
}
public final void set32(int offset, int v32) {
m_data[offset++] = (byte) (v32 & 0xFF);
m_data[offset++] = (byte) ((v32 >> 8) & 0xFF);
m_data[offset++] = (byte) ((v32 >> 16) & 0xFF);
m_data[offset++] = (byte) ((v32 >> 24) & 0xFF);
}
public final void set64(int offset, long v64) {
m_data[offset++] = (byte) (v64 & 0xFF);
m_data[offset++] = (byte) ((v64 >> 8) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 16) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 24) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 32) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 40) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 48) & 0xFF);
m_data[offset++] = (byte) ((v64 >> 56) & 0xFF);
}
public final void set8(int offset, int v8) {
m_data[offset] = (byte) v8;
}
public final ObjectRef setObjectRef(Object label) {
X86ObjectRef ref = (X86ObjectRef) getObjectRef(label);
ref.setOffset(m_used);
return ref;
}
/**
* Sets the resolver.
*
* @param resolver The resolver to set
*/
public void setResolver(ObjectResolver resolver) {
this.resolver = resolver;
}
/**
* Start a new object and write its header. An ObjectInfo object is
* returned, on which the <code>markEnd</code> mehod must be called after
* all data has been written into the object.
*
* @param cls
* @return The info for the started object
* @see ObjectInfo
*/
public final ObjectInfo startObject(VmType<?> cls) {
if (inObject) {
throw new RuntimeException(
"Cannot start an object within an object");
}
if (align(ObjectLayout.OBJECT_ALIGN) != 0) {
throw new RuntimeException("Unaligned before startObject");
}
inObject = true;
// The default header is 2 words long. The size fields add another
// word, which adds up to 3 words which masy not be objectaligned.
// Write some slack until it is aligned again
int alignSlack = 0;
final int threeWords = getWordSize() * 3;
while (ObjectLayout.objectAlign(alignSlack + threeWords) != (alignSlack + threeWords)) {
writeWord(0);
alignSlack += getWordSize();
}
// System.out.println("alignSlack=" + alignSlack);
writeWord(0); // Size
writeWord(ObjectFlags.GC_DEFAULT_COLOR); // Flags
if (cls == null) {
throw new NullPointerException("cls==null");
} else {
final Object[] tib = ((VmClassType<?>) cls).getTIB();
if (tib[0] == null) {
throw new NullPointerException("tib[0]==null");
}
writeObjectRef(tib, 0, false);
}
return new X86ObjectInfo();
}
private void testDst(X86Register dst, int dstDisp) {
if ((dst == X86Register.EBP) && (dstDisp == 0)) {
throw new IllegalArgumentException("Write to [EBP+0]");
}
}
/**
* Dst register must have an 8-bits part. Valid for EAX, EBX, ECX, EDX,
* runtimeexception for others.
*
* @param dst
*/
private void testSuitableForBits8(X86Register dst) {
if (!dst.isSuitableForBits8()) {
throw new IllegalArgumentException("Register " + dst
+ " is not suitable for BITS8 datasize");
}
}
/**
* Remove count bytes from the end of the generated stream.
*
* @param count
*/
public void trim(int count) {
if ((count < 0) || (count > m_used)) {
throw new IllegalArgumentException("Invalid count value " + count);
}
m_used -= count;
}
public final void write(byte[] data, int ofs, int len) {
/*
* if (!inObject) { throw new IllegalArgumentException("Cannot write out
* of an object");
*/
ensureSize(len);
System.arraycopy(data, ofs, m_data, m_used, len);
m_used += len;
}
public final void write16(int v16) {
//if (!inObject) {
// throw new IllegalArgumentException("Cannot write out of an object");
//}
ensureSize(2);
m_data[m_used++] = (byte) (v16 & 0xFF);
m_data[m_used++] = (byte) ((v16 >> 8) & 0xFF);
}
public final void write32(int v32) {
/*
* if (!inObject) { throw new IllegalArgumentException("Cannot write out
* of an object");
*/
ensureSize(4);
m_data[m_used++] = (byte) (v32 & 0xFF);
m_data[m_used++] = (byte) ((v32 >> 8) & 0xFF);
m_data[m_used++] = (byte) ((v32 >> 16) & 0xFF);
m_data[m_used++] = (byte) ((v32 >> 24) & 0xFF);
}
public final void write64(long v64) {
write32((int) (v64 & 0xFFFFFFFF)); // lsb
write32((int) ((v64 >>> 32) & 0xFFFFFFFF)); // msb
}
/**
* Write an 8-bit unsigned byte.
*
* @param v8
*/
public final void write8(int v8) {
ensureSize(1);
m_data[m_used++] = (byte) (v8 & 0xFF);
}
/**
* Create a ADC dstReg, imm32
*
* @param dstReg
* @param imm32
*/
public void writeADC(GPR dstReg, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 2);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 2);
write32(imm32);
}
}
public void writeADC(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 2);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 2);
write32(imm32);
}
}
/**
* Create a ADC [dstReg+dstDisp], <srcReg>
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeADC(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRM(0x11, srcReg.getSize(), dstReg, dstDisp, srcReg
.getNr());
}
/**
* Create a ADC dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public void writeADC(GPR dstReg, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRR(0x11, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* Create a ADC dstReg, [srcReg+srcDisp]
*
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeADC(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRM(0x13, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
/**
* Create an ADD dstReg, imm32
*
* @param dstReg
* @param imm32
*/
public void writeADD(GPR dstReg, int imm32) {
testSize(dstReg, BITS32 | BITS64);
if (dstReg == GPR.EAX && !isByte(imm32)) {
write8(0x05);
write32(imm32);
} else if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 0);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 0);
write32(imm32);
}
}
/**
* Create a ADD [dstReg+dstDisp], imm32
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeADD(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 0);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 0);
write32(imm32);
}
}
public void writeADD(int operandSize, SR dstReg, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
if (isUByte(imm32) || isByte(imm32)) {
write8(0x83);
write8(0x05);
write32(dstDisp);
write8(imm32);
} else {
write8(0x81);
write8(0x05);
write32(dstDisp);
write32(imm32);
}
}
public void writeADD_MEM(X86Register.GPR reg, int memPtr) {
testSize(reg, mode.getSize());
if (code64) {
throw new InvalidOpcodeException("Not implemented");
}
write8(0x03); // opcode
write8((reg.getNr() << 3) | 5); // disp32
write32(memPtr);
}
/**
* Create a ADD [dstDisp], imm32
*
* @param operandSize
* @param dstDisp
* @param imm32
*/
public void writeADD(int operandSize, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
switch (operandSize) {
case BITS8:
write1bOpcodeModMem(0x80, operandSize, dstDisp, 0);
write8(imm32);
break;
case BITS16:
write8(OSIZE_PREFIX);
write1bOpcodeModMem(0x81, operandSize, dstDisp, 0);
write16(imm32);
break;
case BITS32:
if (isByte(imm32)) { //todo review
write8(0x83);
write8(0x05);
write32(dstDisp);
write8(imm32);
} else {
write1bOpcodeModMem(0x81, operandSize, dstDisp, 0);
write32(imm32);
}
break;
}
}
/**
* Create a ADD [dstReg+dstDisp], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeADD(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRM(0x01, srcReg.getSize(), dstReg, dstDisp, srcReg
.getNr());
}
/**
* Create a ADD dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeADD(GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRR(0x01, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* Create a ADD dstReg, [srcReg+srcDisp]
*
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public final void writeADD(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRM(0x03, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
/**
* Create a AND dstReg, imm32
*
* @param dstReg
* @param imm32
*/
public final void writeAND(GPR dstReg, int imm32) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
int size = dstReg.getSize();
if (dstReg == GPR.AL) {
write8(0x24);
write8(imm32);
} else if (dstReg == GPR.EAX && !isByte(imm32)) {
write8(0x25);
write32(imm32);
} else if ((size & (BITS32 | BITS64)) == size) {
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 4);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 4);
write32(imm32);
}
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 4);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 4);
write16(imm32);
}
} else if (size == BITS8) {
write1bOpcodeModRR(0x80, dstReg.getSize(), dstReg, 4);
write8(imm32);
}
}
/**
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeAND(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 4);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 4);
write32(imm32);
}
}
/**
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeAND(int operandSize, SR dstReg, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
//todo review
if (isUByte(imm32) || isByte(imm32)) {
write8(0x83);
write8(0x25);
write32(dstDisp);
write8(imm32);
} else {
write8(0x81);
write8(0x25);
write32(dstDisp);
write32(imm32);
}
}
/**
* @param operandSize
* @param dstDisp
* @param imm32
*/
public void writeAND(int operandSize, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
switch (operandSize) {
case BITS8: //todo review
write8(0x80);
write8(0x25);
write32(dstDisp);
break;
case BITS16:
write8(OSIZE_PREFIX);
write1bOpcodeModMem(0x81, operandSize, dstDisp, 4);
break;
case BITS32:
write1bOpcodeModMem(0x81, operandSize, dstDisp, 4);
break;
}
write8(imm32);
}
/**
* Create a AND [dstReg+dstDisp], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeAND(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, BITS8 | BITS16 | BITS32 | BITS64);
int size = srcReg.getSize();
if ((size & (BITS32 | BITS64)) == size) {
write1bOpcodeModRM(0x21, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRM(0x21, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS8) {
write1bOpcodeModRM(0x20, size, dstReg, dstDisp, srcReg.getNr());
}
}
/**
* Create a AND dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeAND(GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRR(0x21, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeAND(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRM(0x23, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
public void writeArithSSEDOp(int operation, XMM dst, GPR src, int srcDisp) {
final int opcode3 = sseOperationToOpcode3(operation);
write3bOpcodeModRM(0xF2, 0x0F, opcode3, 0, src, srcDisp, dst.getNr());
}
public void writeArithSSEDOp(int operation, XMM dst, XMM src) {
final int opcode3 = sseOperationToOpcode3(operation);
write3bOpcodeModRR(0xF2, 0x0F, opcode3, 0, src, dst.getNr());
}
public void writeArithSSESOp(int operation, XMM dst, GPR src, int srcDisp) {
final int opcode3 = sseOperationToOpcode3(operation);
write3bOpcodeModRM(0xF3, 0x0F, opcode3, 0, src, srcDisp, dst.getNr());
}
public void writeArithSSESOp(int operation, XMM dst, XMM src) {
final int opcode3 = sseOperationToOpcode3(operation);
write3bOpcodeModRR(0xF3, 0x0F, opcode3, 0, src, dst.getNr());
}
/**
* Convert an SSE operation into the 3'rd opcode byte for that operation.
*
* @param operation
* @return the 3'rd opcode byte.
*/
private final int sseOperationToOpcode3(int operation) {
final int opcode3;
switch (operation) {
case SSE_ADD:
opcode3 = 0x58;
break;
case SSE_SUB:
opcode3 = 0x5C;
break;
case SSE_MUL:
opcode3 = 0x59;
break;
case SSE_DIV:
opcode3 = 0x5E;
break;
default:
throw new IllegalArgumentException("Invalid SSE operation "
+ operation);
}
return opcode3;
}
/**
* Create a bound lReg, [rReg+rDisp]
*
* @param lReg
* @param rReg
* @param rDisp
*/
public final void writeBOUND(GPR lReg, GPR rReg, int rDisp) {
if (code64) {
throw new InvalidOpcodeException();
}
write1bOpcodeModRM(0x62, 0, rReg, rDisp, lReg.getNr());
}
/**
* @see org.jnode.assembler.x86.X86Assembler#writeBreakPoint()
*/
public void writeBreakPoint() {
write8(0xCC);
}
@Override
public void writeBTS(GPR reg, int imm8) {
write8(0x0F); //todo
write8(0xBA);
writeModRM(0, 0, reg.getNr());
write8(imm8);
}
/**
* Create a relative call to a given label
*
* @param label
*/
public final void writeCALL(Label label) {
write8(0xe8); // call rel32
writeRelativeObjectRef(label);
}
/**
* Create a call to address stored at the given offset in the given table
* pointer.
*
* @param tablePtr
* @param offset
* @param rawAddress If true, tablePtr is a raw address
*/
public final void writeCALL(Object tablePtr, int offset, boolean rawAddress) {
if (code64) {
throw new InvalidOpcodeException();
}
write8(0xFF); // Opcode
write8(0x15); // effective address == disp32
writeObjectRef(tablePtr, offset, rawAddress);
}
public void writeCALL(GPR reg) {
testSize(reg, mode.getSize());
// Since CALL in 64-bit mode always use 64-bit targets, we
// specify a 0 operand size, so we won't get a REX prefix
write1bOpcodeModRR(0xFF, 0, reg, 2);
}
/**
* Create a call to address stored at the given [reg+offset].
*
* @param reg
* @param offset
*/
public final void writeCALL(GPR reg, int offset) {
// Since CALL in 64-bit mode always use 64-bit targets, we
// specify a 0 operand size, so we won't get a REX prefix
write1bOpcodeModRM(0xFF, 0, reg, offset, 2);
}
/**
* Create a call to address stored at the given [reg+offset].
*
* @param reg
* @param offset
*/
public final void writeCALL_FAR(GPR reg, int offset) {
// Since CALL in 64-bit mode always use 64-bit targets, we
// specify a 0 operand size, so we won't get a REX prefix
write1bOpcodeModRM(0xFF, 0, reg, offset, 3);
}
public void writeCALL(GPR regBase, GPR regIndex, int scale, int disp) {
// Since CALL in 64-bit mode always use 64-bit targets, we
// specify a 0 operand size, so we won't get a REX prefix
write1bOpcodeModRMSib(0xFF, 0, regBase, disp, 2, scale, regIndex);
}
public void writeCALL(GPR regIndex, int scale, int disp) {
testOperandSize(BITS32, mode.getSize());
switch (scale) {
case 1:
scale = 0;
break;
case 2:
scale = 1;
break;
case 4:
scale = 2;
break;
case 8:
scale = 3;
break;
default:
throw new IllegalArgumentException("scale");
}
//TODO review
write8(0xFF);
write8(0x14);
write8(0x05 | regIndex.getNr() << 3 | scale << 6);
write32(disp);
}
/**
* Create a cdq
* Sign extend EAX to EDX:EAX in 32-bit operand size.
* Sign extend RAX to RDX:RAX in 64-bit operand size.
*/
public final void writeCDQ(int operandSize) {
testOperandSize(operandSize, BITS32 | BITS64);
if (operandSize == BITS64) {
if (!code64) {
throw new InvalidOpcodeException();
}
write8(REX_W_PREFIX);
}
write8(0x99);
}
/**
* Create a cdqe. Sign extend EAX to RAX. Only valid in 64-bit mode.
*/
public void writeCDQE() throws InvalidOpcodeException {
if (!code64) {
throw new InvalidOpcodeException();
}
write8(REX_W_PREFIX);
write8(0x98);
}
public void writeCLD() {
write8(0xFC);
}
public void writeCLI() {
write8(0xFA);
}
public void writeCLTS() {
write8(CRX_PREFIX);
write8(0x06);
}
/**
* Create a CMOVcc dst,src
*
* @param ccOpcode
* @param dst
* @param src
*/
public void writeCMOVcc(int ccOpcode, GPR dst, GPR src) {
if (!haveCMOV) {
throw new InvalidOpcodeException("CMOVcc not supported");
}
write2bOpcodeModRR(0x0F, ccOpcode - 0x40, src.getSize(), src, dst
.getNr());
}
/**
* Create a CMOVcc dst,[src+srcDisp]
*
* @param dst
* @param src
* @param srcDisp
*/
public void writeCMOVcc(int ccOpcode, GPR dst, GPR src, int srcDisp) {
if (!haveCMOV) {
throw new InvalidOpcodeException("CMOVcc not supported");
}
write2bOpcodeModRM(0x0F, ccOpcode - 0x40, dst.getSize(), src, srcDisp,
dst.getNr());
}
/**
* Create a CMP [reg1+disp], reg2
*
* @param reg1
* @param disp
* @param reg2
*/
public void writeCMP(GPR reg1, int disp, GPR reg2) {
testSize(reg1, BITS32 | BITS64);
testSize(reg2, BITS32 | BITS64);
write1bOpcodeModRM(0x39, reg2.getSize(), reg1, disp, reg2.getNr());
}
/**
* Create a CMP reg1, reg2
*
* @param reg1
* @param reg2
*/
public final void writeCMP(GPR reg1, GPR reg2) {
testSize(reg1, BITS32 | BITS64);
testSize(reg2, BITS32 | BITS64);
write1bOpcodeModRR(0x39, reg1.getSize(), reg1, reg2.getNr());
}
/**
* Create a CMP reg1, [reg2+disp]
*
* @param reg1
* @param reg2
* @param disp
*/
public void writeCMP(GPR reg1, SR reg2, int disp) {
testSize(reg1, BITS32);
writeSegPrefix(reg2);
write8(0x3b);
write8(0x05 | reg1.getNr() << 3);
write32(disp);
}
/**
* Create a CMP reg1, [reg2+disp]
*
* @param reg1
* @param reg2
* @param disp
*/
public void writeCMP(GPR reg1, GPR reg2, int disp) {
testSize(reg1, BITS32 | BITS64);
testSize(reg2, BITS32 | BITS64);
write1bOpcodeModRM(0x3b, reg1.getSize(), reg2, disp, reg1.getNr());
}
/**
* Create a CMP reg, imm32
*
* @param reg
* @param imm32
*/
public final void writeCMP_Const(GPR reg, int imm32) {
testSize(reg, BITS8 | BITS16 | BITS32 | BITS64);
int size = reg.getSize();
if ((size & (BITS32 | BITS64)) == size) {
if (reg == GPR.AL) {
write8(0x3c);
write8(imm32);
} else if ((reg == GPR.EAX || reg == GPR.RAX) && (!isByte(imm32) || imm32 == 0)) {
writeCMP_EAX(size, imm32);
} else if (isByte(imm32) && imm32 != 0) {
write1bOpcodeModRR(0x83, reg.getSize(), reg, 7);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, reg.getSize(), reg, 7);
write32(imm32);
}
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, reg.getSize(), reg, 7);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, reg.getSize(), reg, 7);
write16(imm32);
}
} else if (size == BITS8) {
if (reg == GPR.AL) {
write8(0x3c);
write8(imm32);
} else {
write1bOpcodeModRR(0x80, reg.getSize(), reg, 7);
write8(imm32);
}
}
}
/**
* Create a CMP [reg+disp], imm32
*
* @param reg
* @param disp
* @param imm32
*/
public void writeCMP_Const(int operandSize, GPR reg, int disp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS32 | BITS64);
if (operandSize == BITS8) {
write1bOpcodeModRM(0x80, operandSize, reg, disp, 7);
write8(imm32);
} else if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, reg, disp, 7);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, reg, disp, 7);
write32(imm32);
}
}
/**
* Create a CMP [reg:disp], imm32
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeCMP_Const(int operandSize, SR dstReg, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
if (isUByte(imm32)) {
write8(0x83);
write8(0x3d);
write32(dstDisp);
write8(imm32);
} else {
write8(0x81);
write8(0x3d);
write32(dstDisp);
write32(imm32);
}
}
/**
* Create a CMP eax,imm32 or CMP rax,imm32
*
* @param imm32
*/
public final void writeCMP_EAX(int operandSize, int imm32) {
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeREXPrefix(operandSize, 0);
write8(0x3d);
write32(imm32);
}
/**
* Create a CMP [reg+regDisp], imm32
*
* @param memPtr
* @param imm32
*/
public final void writeCMP_MEM(int operandSize, int memPtr, int imm32) {
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeREXPrefix(operandSize, 0);
if (isByte(imm32)) {
write8(0x83); // Opcode
write8(0x3D); // effective address == disp32
write32(memPtr);
write8(imm32);
} else {
write8(0x81); // Opcode
write8(0x3D); // effective address == disp32
write32(memPtr);
write32(imm32);
}
}
/**
* Create a CMP reg,[memPtr]
*
* @param reg
* @param memPtr
*/
public void writeCMP_MEM(GPR reg, int memPtr) {
testSize(reg, mode.getSize());
if (code64) {
throw new InvalidOpcodeException("Not implemented");
}
write8(0x3b); // opcode
write8((reg.getNr() << 3) | 5); // disp32
write32(memPtr);
}
/**
* Create a CMPXCHG dword [dstReg], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
* @param lock
*/
public final void writeCMPXCHG_EAX(GPR dstReg, int dstDisp, GPR srcReg,
boolean lock) {
if (lock) {
write8(0xF0);
}
write2bOpcodeModRM(0x0F, 0xB1, srcReg.getSize(), dstReg, dstDisp,
srcReg.getNr());
}
/**
*
*/
public void writeCPUID() {
write8(CRX_PREFIX);
write8(0xA2);
}
/**
* Create a dec reg32
*
* @param dstReg
*/
public final void writeDEC(GPR dstReg) {
testSize(dstReg, BITS32 | BITS64);
if (code32) {
write8(0x48 + dstReg.getNr());
} else {
write1bOpcodeModRR(0xFF, dstReg.getSize(), dstReg, 1);
}
}
/**
* Create a dec dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeDEC(int operandSize, GPR dstReg, int dstDisp) {
testSize(dstReg, mode.getSize());
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRM(0xff, operandSize, dstReg, dstDisp, 1);
}
/**
* Create an div edx:eax, srcReg.
* <p/>
* If srcReg is 64-bit, the div rdx:rax, srcReg is created.
*
* @param srcReg
*/
public final void writeDIV_EAX(GPR srcReg) {
write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 6);
}
public void writeEMMS() {
write8(0x0F);
write8(0x77);
}
/**
* Create a fadd dword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFADD32(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 0);
}
/**
* Create a fadd qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFADD64(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 0);
}
public void writeFADDP(X86Register fpuReg) {
write8(0xde);
write8(0xc0 + fpuReg.getNr());
}
/**
* Create a fchs
*/
public final void writeFCHS() {
write8(0xd9);
write8(0xe0);
}
/**
* Create a fdiv dword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFDIV32(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 6);
}
/**
* Create a fdiv qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFDIV64(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 6);
}
public void writeFDIVP(X86Register fpuReg) {
write8(0xde);
write8(0xf8 + fpuReg.getNr());
}
/**
* Create a ffree
*
* @param fReg
*/
public final void writeFFREE(X86Register fReg) {
write8(0xdd);
write8(0xc0 | fReg.getNr());
}
/**
* Create a fild dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFILD32(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xdb, 0, dstReg, dstDisp, 0);
}
/**
* Create a fild qword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFILD64(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xdf, 0, dstReg, dstDisp, 5);
}
/**
* Create a fistp dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFISTP32(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xdb, 0, dstReg, dstDisp, 3);
}
/**
* Create a fistp qword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFISTP64(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xdf, 0, dstReg, dstDisp, 7);
}
/**
* Create a fld dword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFLD32(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xd9, 0, srcReg, srcDisp, 0);
}
/**
* Create a fld dword [srcBaseReg+scrIndexReg*srcScale+srcDisp]
*
* @param srcBaseReg
* @param srcIndexReg
* @param srcScale
* @param srcDisp
*/
public void writeFLD32(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
int srcDisp) {
write1bOpcodeModRMSib(0xd9, 0, srcBaseReg, srcDisp, 0, srcScale,
srcIndexReg);
}
/**
* Create a fld qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFLD64(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xdd, 0, srcReg, srcDisp, 0);
}
/**
* Create a fld qword [srcBaseReg+scrIndexReg*srcScale+srcDisp]
*
* @param srcBaseReg
* @param srcIndexReg
* @param srcScale
* @param srcDisp
*/
public void writeFLD64(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
int srcDisp) {
write1bOpcodeModRMSib(0xdd, 0, srcBaseReg, srcDisp, 0, srcScale,
srcIndexReg);
}
/**
* Create a fldcw word [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFLDCW(GPR srcReg, int srcDisp) {
write8(0xd9);
writeModRM(srcReg.getNr() & 7, srcDisp, 5);
}
/**
* Create a fmul dword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFMUL32(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 1);
}
/**
* Create a fmul qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFMUL64(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 1);
}
public void writeFMULP(X86Register fpuReg) {
write8(0xde);
write8(0xc8 + fpuReg.getNr());
}
/**
* Create a fninit
*/
public final void writeFNINIT() {
write8(0xdb);
write8(0xe3);
}
/**
* Create a fnsave [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFNSAVE(GPR srcReg, int srcDisp) {
write8(0xdd);
writeModRM(srcReg.getNr() & 7, srcDisp, 6);
}
/**
* Create a fnstsw, Store fp status word in AX
*/
public final void writeFNSTSW_AX() {
write8(0xdf);
write8(0xe0);
}
/**
* Create a fprem
*/
public final void writeFPREM() {
write8(0xd9);
write8(0xf8);
}
/**
* Create a frstor [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFRSTOR(GPR srcReg, int srcDisp) {
write8(0xdd);
writeModRM(srcReg.getNr() & 7, srcDisp, 4);
}
/**
* Create a fstcw word [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFSTCW(GPR srcReg, int srcDisp) {
write8(0x9b);
write8(0xd9);
if (srcDisp == 0) {
write8(0x00 | (7 << 3) | srcReg.getNr() & 7); //fstcw
write8(0x24);
} else {
writeModRM(srcReg.getNr() & 7, srcDisp, 7);
}
}
public void writeFSTP(X86Register fpuReg) {
write8(0xDD);
write8(0xD8 + fpuReg.getNr());
}
/**
* Create a fstp dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFSTP32(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xd9, 0, dstReg, dstDisp, 3);
}
/**
* Create a fstp qword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeFSTP64(GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xdd, 0, dstReg, dstDisp, 3);
}
/**
* Create a fsub dword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFSUB32(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 4);
}
/**
* Create a fsub qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFSUB64(GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 4);
}
public void writeFSUBP(X86Register fpuReg) {
write8(0xde);
write8(0xe8 + fpuReg.getNr());
}
/**
* Create a fucompp, Compare - Pop twice
*/
public final void writeFUCOMPP() {
write8(0xda);
write8(0xe9);
}
public void writeFXCH(X86Register fpuReg) {
write8(0xd9);
write8(0xc8 + fpuReg.getNr());
}
/**
* Create a fxrstor [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFXRSTOR(GPR srcReg, int srcDisp) {
write8(0x0f);
write8(0xae);
writeModRM(srcReg.getNr() & 7, srcDisp, 1);
}
/**
* Create a fxsave [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
*/
public final void writeFXSAVE(GPR srcReg, int srcDisp) {
write8(0x0f);
write8(0xae);
writeModRM(srcReg.getNr() & 7, srcDisp, 0);
}
public void writeHLT() {
write8(0xF4);
}
/**
* Create an idiv edx:eax, srcReg.
* If srcReg is 64-bit, the idiv rdx:rax, srcReg is created.
*
* @param srcReg
*/
public final void writeIDIV_EAX(GPR srcReg) {
write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 7);
}
/**
* @param srcReg
* @param srcDisp
*/
public void writeIDIV_EAX(int operandSize, GPR srcReg, int srcDisp) {
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRM(0xF7, operandSize, srcReg, srcDisp, 7);
}
/**
* @param dstReg
* @param srcReg
*/
public void writeIMUL(GPR dstReg, GPR srcReg) {
write2bOpcodeModRR(0x0F, 0xAF, srcReg.getSize(), srcReg, dstReg.getNr());
}
/**
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeIMUL(GPR dstReg, GPR srcReg, int srcDisp) {
write2bOpcodeModRM(0x0F, 0xAF, dstReg.getSize(), srcReg, srcDisp,
dstReg.getNr());
}
/**
* @param dstReg
* @param srcReg
* @param imm32
*/
public void writeIMUL_3(GPR dstReg, GPR srcReg, int imm32) {
write1bOpcodeModRR(0x69, dstReg.getSize(), srcReg, dstReg.getNr());
write32(imm32);
}
/**
* @param dstReg
* @param srcReg
* @param srcDisp
* @param imm32
*/
public void writeIMUL_3(GPR dstReg, GPR srcReg, int srcDisp, int imm32) {
write1bOpcodeModRM(0x69, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
write32(imm32);
}
/**
* Create a imul eax, srcReg.
* <p/>
* If srcReg is 64-bit, an imul rax, srcReg is created.
*
* @param srcReg
*/
public final void writeIMUL_EAX(GPR srcReg) {
write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 5);
}
public void writeIN(int operandSize) {
if (operandSize == X86Constants.BITS8) {
write8(0xEC);
} else if (operandSize == X86Constants.BITS16) {
write8(X86Constants.OSIZE_PREFIX);
write8(0xED);
} else if (operandSize == X86Constants.BITS32) {
write8(0xED);
} else {
throw new IllegalArgumentException("Invalid operand size for IN: " + operandSize);
}
}
public void writeIN(int operandSize, int imm8) {
if (operandSize == X86Constants.BITS8) {
write8(0xE4);
write8(imm8);
} else if (operandSize == X86Constants.BITS16) {
write8(X86Constants.OSIZE_PREFIX);
write8(0xE5);
write8(imm8);
} else if (operandSize == X86Constants.BITS32) {
write8(0xE5);
write8(imm8);
} else {
throw new IllegalArgumentException("Invalid operand size for IN: " + operandSize);
}
}
/**
* Create a inc reg32
*
* @param dstReg
*/
public final void writeINC(GPR dstReg) {
testSize(dstReg, BITS32 | BITS64);
if (code32) {
write8(0x40 + dstReg.getNr());
} else {
write1bOpcodeModRR(0xFF, dstReg.getSize(), dstReg, 0);
}
}
/**
* Create a inc size [dstReg:disp]
*
* @param dstReg
*/
public final void writeINC(int operandSize, SR dstReg, int disp) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
write8(0xff);
write8(0x05);
write32(disp);
}
/**
* Create a inc size [dstReg+disp]
*
* @param dstReg
*/
public final void writeINC(int operandSize, GPR dstReg, int disp) {
testSize(dstReg, mode.getSize());
testOperandSize(operandSize, BITS8 | BITS16 | BITS32 | BITS64);
if (operandSize == BITS32 || operandSize == BITS64) {
write1bOpcodeModRM(0xFF, operandSize, dstReg, disp, 0);
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRM(0xFF, operandSize, dstReg, disp, 0);
} else if (operandSize == BITS8) {
write1bOpcodeModRM(0xFE, operandSize, dstReg, disp, 0);
}
}
/**
* Create a inc size [dstReg+disp]
*
* @param dstReg
*/
public final void writeINC(int operandSize, GPR dstReg, GPR dstIdxReg, int scale, int disp) {
testSize(dstReg, mode.getSize());
testSize(dstIdxReg, mode.getSize());
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRMSib(0xFF, operandSize, dstReg, disp, 0, scale, dstIdxReg);
}
/**
* Create a inc size [dstReg+disp]
*
* @param operandSize
* @param dstDisp
*/
public final void writeINC(int operandSize, int dstDisp) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
//TODO review
if (operandSize == BITS32) {
write8(0xFF);
write8(5);
write32(dstDisp);
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
write8(0xFF);
write8(5);
write32(dstDisp);
} else if (operandSize == BITS8) {
write8(0xFE);
write8(5);
write32(dstDisp);
}
}
/**
* Create a int vector
*
* @param vector
*/
public final void writeINT(int vector) {
write8(0xCD);
write8(vector);
}
/**
*
*/
public void writeIRET() {
write8(0xCF);
}
/**
*
*/
public void writeIRETQ() {
write8(REX_W_PREFIX);
write8(0xCF);
}
/**
* Create a conditional jump to a label.
*
* @param label
* @param jumpOpcode
*/
public final void writeJCC(Label label, int jumpOpcode) {
final ObjectRef ref = getObjectRef(label);
final int shortOffset = m_used + 2;
if (ref.isResolved() && isByteDistance(ref, shortOffset) && isRelJumpEnabled()) {
try {
// We can do a short jump
write8(jumpOpcode - 0x10); // jcc imm8
write8(ref.getOffset() - shortOffset);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
} else {
write8(0x0f); // jxx rel32
write8(jumpOpcode);
writeRelativeObjectRef(label);
}
}
public final void writeJECXZ(Label label) {
final ObjectRef ref = getObjectRef(label);
final int shortOffset = m_used + 2;
if (ref.isResolved()) {
if (isByteDistance(ref, shortOffset)) {
try {
write8(0xE3);
write8(ref.getOffset() - shortOffset);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
} else {
try {
throw new IllegalArgumentException("Invalid jump distance: " + (ref.getOffset() - shortOffset));
} catch (UnresolvedObjectRefException rex) {
throw new RuntimeException(rex);
}
}
} else {
write8(0xE3);
final int ofs = m_used + 1;
final X86ObjectRef xref = (X86ObjectRef) getObjectRef(label);
xref.setRelJump();
if (xref.isResolved()) {
try {
write8(xref.getOffset() - ofs);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
} else {
xref.addUnresolvedLink(m_used, 1);
write8(ofs);
}
}
}
//TODO this method does not handle the forward jumps correctly, needs further work.
//Also the general purpose version of the method writeJCC(Lable lebal, int jumpcode)
//for handling byte sized target for the jump would renders this method unnecessary.
/**
* Create a LOOP label instruction. The given label must have be resolved
* before!
*
* @param label
*/
public final void writeJECXZ0(Label label) {
final ObjectRef ref = getObjectRef(label);
write8(0x67);
write8(0xE3);
final int offset = m_used + 1;
if (ref.isResolved()) {
try {
int distance = ref.getOffset() - offset;
if (X86Utils.isByte(distance)) {
write8(distance);
} else {
throw new UnresolvedObjectRefException("Label " + label
+ " is out of range (distance " + distance + ')');
}
} catch (UnresolvedObjectRefException x) {
throw new RuntimeException(x);
}
} else {
ref.addUnresolvedLink(m_used, 1);
write8(offset);
}
}
/**
* Create a relative jump to a given label
*
* @param label
*/
public final void writeJMP(Label label) {
final ObjectRef ref = getObjectRef(label);
final int shortOffset = m_used + 2;
if (ref.isResolved() && isByteDistance(ref, shortOffset) && isRelJumpEnabled()) {
try {
// We can do a short jump
write8(0xEB); // jmp imm8
write8(ref.getOffset() - shortOffset);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
} else {
write8(0xe9); // jmp rel32
writeRelativeObjectRef(label);
}
}
private final boolean isByteDistance(ObjectRef ref, int offset) {
try {
final int distance = ref.getOffset() - offset;
return X86Utils.isByte(distance);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
}
/**
* Create a absolute jump to address stored at the given offset in the given
* table pointer.
*
* @param tablePtr
* @param offset
* @param rawAddress If true, tablePtr is a raw address
*/
public void writeJMP(Object tablePtr, int offset, boolean rawAddress) {
if (code64) {
throw new InvalidOpcodeException();
}
write8(0xFF); // Opcode
write8(0x25); // effective address == disp32
writeObjectRef(tablePtr, offset, rawAddress);
}
/**
* Create a absolute jump to address stored at the given offset (in
* register) in the given table pointer.
*
* @param tablePtr
* @param offsetReg
*/
public void writeJMP(Object tablePtr, GPR offsetReg) {
write2bOpcodeReg(0xFF, 0xA0, offsetReg);
// effective address == disp32[reg]
writeObjectRef(tablePtr, 0, false);
}
/**
* Create a absolute jump to address in register.
*
* @param reg
*/
public final void writeJMP(GPR reg) {
testSize(reg, mode.getSize());
// Since JMP defaults to 64-bit in 64-bit mode, we give 0 as
// operand size to avoid a REX prefix.
write1bOpcodeModRR(0xff, 0, reg, 4);
}
/**
* Create a absolute jump to [reg+disp]
*
* @param reg
* @param disp
*/
public final void writeJMP(GPR reg, int disp) {
testSize(reg, mode.getSize());
if (isByte(disp)) {
write2bOpcodeReg(0xFF, 0x60, reg);
write8(disp);
} else {
write2bOpcodeReg(0xFF, 0xA0, reg);
write32(disp);
}
}
/**
* Create a absolute jump to disp1:disp2
*
* @param seg
* @param disp
*/
public final void writeJMP(int operandSize, int seg, int disp) {
testOperandSize(operandSize, BITS16 | BITS32);
testOperandSize(mode.getSize(), BITS32);
if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
}
write8(0xea);
if (operandSize == BITS16) {
write16(disp);
} else {
write32(disp);
}
write16(seg);
}
/**
* Create a ldmxcsr dword [srcReg+disp]
*
* @param srcReg
* @param disp
*/
public final void writeLDMXCSR(GPR srcReg, int disp) {
write8(0x0f);
write8(0xae);
writeModRM(srcReg.getNr() & 7, disp, 2);
}
/**
* Create a lea dstReg,[srcReg+disp]
*
* @param dstReg
* @param srcReg
* @param disp
*/
public final void writeLEA(GPR dstReg, GPR srcReg, int disp) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
//write1bOpcodeModRM(0x8d, dstReg.getSize(), srcReg, disp, dstReg.getNr());
//TODO review
//private final void write1bOpcodeModRM(int opcode, int operandSize, GPR rm, int disp, int reg)
if (true) {
int opcode = 0x8d;
int operandSize = dstReg.getSize();
GPR rm = srcReg;
int reg = dstReg.getNr();
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode);
//writeModRM(rm.getNr() & 7, disp, reg & 7);
}
//private final void writeModRM(int rm, int disp, int reg) {
int rm = srcReg.getNr() & 7;
int reg = dstReg.getNr() & 7;
if ((rm < 0) || (rm > 7)) {
throw new IllegalArgumentException("rm");
}
if ((reg < 0) || (reg > 7)) {
throw new IllegalArgumentException("reg");
}
if (rm == X86Register.ESP.getNr()) {
if (disp == 0 && false) { //TODO review
write8(0x00 | (reg << 3) | rm);
write8(0x24);
} else if (isByte(disp)) {
write8(0x40 | (reg << 3) | rm);
write8(0x24);
write8(disp);
} else {
write8(0x80 | (reg << 3) | rm);
write8(0x24);
write32(disp);
}
} else {
if ((disp == 0) && (rm != X86Register.EBP.getNr()) && false) { //TODO review
write8(0x00 | (reg << 3) | rm);
} else if (isByte(disp)) {
write8(0x40 | (reg << 3) | rm);
write8(disp);
} else {
write8(0x80 | (reg << 3) | rm);
write32(disp);
}
}
//}
}
/**
* Create a lea dstReg,[srcReg+srcIdxReg*scale+disp]
*
* @param dstReg
* @param srcReg
* @param srcIdxReg
* @param scale
* @param disp
*/
public final void writeLEA(GPR dstReg, GPR srcReg, GPR srcIdxReg,
int scale, int disp) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
testSize(srcIdxReg, mode.getSize());
write1bOpcodeModRMSib(0x8d, dstReg.getSize(), srcReg, disp, dstReg
.getNr(), scale, srcIdxReg);
}
/**
* Create a lea dstReg,[srcReg+srcIdxReg*scale+disp]
*
* @param dstReg
* @param srcIdxReg
* @param scale
* @param disp
*/
public final void writeLEA(GPR dstReg, GPR srcIdxReg, int scale, int disp) {
testSize(dstReg, mode.getSize());
testSize(srcIdxReg, mode.getSize());
switch (scale) {
case 1:
scale = 0;
break;
case 2:
scale = 1;
break;
case 4:
scale = 2;
break;
case 8:
scale = 3;
break;
default:
throw new IllegalArgumentException("scale");
}
//TODO review
write8(0x8d);
write8(0x04 | dstReg.getNr() << 3);
write8(0x05 | srcIdxReg.getNr() << 3 | scale << 6);
write32(disp);
}
public final void writeLGDT(int disp) {
testOperandSize(mode.getSize(), BITS32);
//TODO review
write8(0x0f);
write8(0x01);
write8(0x15);
write32(disp);
}
public final void writeLIDT(int disp) {
testOperandSize(mode.getSize(), BITS32);
//TODO review
write8(0x0f);
write8(0x01);
write8(0x1d);
write32(disp);
}
/**
* Create a lmsw srcReg
*
* @param srcReg
*/
public final void writeLMSW(GPR srcReg) {
testSize(srcReg, X86Constants.BITS16);
write8(0x0f);
write8(0x01);
writeModRR(srcReg.getNr() & 7, 6);
}
/**
* Create a LODSD
*/
public final void writeLODSD() {
write8(0xAD);
}
/**
* Create a LODSW
*/
public final void writeLODSW() {
write8(OSIZE_PREFIX);
write8(0xAD);
}
/**
* Create a LOOP label instruction. The given label must have be resolved
* before!
*
* @param label
* @throws UnresolvedObjectRefException
*/
public final void writeLOOP(Label label)
throws UnresolvedObjectRefException {
final ObjectRef ref = getObjectRef(label);
if (ref.isResolved()) {
write8(0xE2);
final int offset = m_used + 1;
int distance = ref.getOffset() - offset;
if (X86Utils.isByte(distance)) {
write8(distance);
} else {
throw new UnresolvedObjectRefException("Label " + label
+ " is out of range (distance " + distance + ')');
}
} else {
throw new UnresolvedObjectRefException("Label " + label
+ " is not resolved");
}
}
/**
* Create a ltr word reg
*
* @param srcReg
*/
public final void writeLTR(GPR srcReg) {
testSize(srcReg, X86Constants.BITS16);
write8(0x0f);
write8(0x00);
writeModRR(srcReg.getNr() & 7, 3);
}
/**
* Write a REX prefix byte if needed for ModRM and ModRR encoded opcodes.
*
* @param operandSize
* @param reg
*/
private final void write1bOpcodeREXPrefix(int operandSize, int reg) {
int rex = 0;
if (operandSize == BITS64) {
rex |= REX_W_PREFIX;
}
if (reg > 7) {
rex |= REX_B_PREFIX;
}
if (rex != 0) {
write8(rex);
}
}
/**
* Write a 1 byte opcode that has the register encoded in the single byte.
*
* @param opcode1
* @param reg
*/
private final void write1bOpcodeReg(int opcode1, X86Register reg) {
write1bOpcodeREXPrefix(reg.getSize(), reg.getNr());
write8(opcode1 + (reg.getNr() & 7));
}
/**
* Write a 2 byte opcode that has the register encoded in the single byte.
*
* @param opcode1
* @param opcode2
* @param reg
*/
private final void write2bOpcodeReg(int opcode1, int opcode2, X86Register reg) {
write1bOpcodeREXPrefix(reg.getSize(), reg.getNr());
write8(opcode1);
write8(opcode2 + (reg.getNr() & 7));
}
/**
* Write a REX prefix byte if needed for ModRM and ModRR encoded opcodes.
*
* @param rm
* @param reg
*/
private final void writeModRMRREXPrefix(int operandSize, X86Register rm,
int reg) {
int rex = 0;
if (operandSize == BITS64) {
rex |= REX_W_PREFIX;
}
if ((rm != null) && (rm.getNr() > 7)) {
rex |= REX_B_PREFIX;
}
if (reg > 7) {
rex |= REX_R_PREFIX;
}
if (rex != 0) {
write8(rex);
}
}
/**
* Write a REX prefix byte if needed.
*
* @param operandSize
* @param base
* @param reg
* @param index
*/
private final void writeModRMSibREXPrefix(int operandSize, GPR base,
int reg, GPR index) {
int rex = 0;
if (operandSize == BITS64) {
rex |= REX_W_PREFIX;
}
if (base.getNr() > 7) {
rex |= REX_B_PREFIX;
}
if (reg > 7) {
rex |= REX_R_PREFIX;
}
if (index.getNr() > 7) {
rex |= REX_X_PREFIX;
}
if (rex != 0) {
write8(rex);
}
}
/**
* Write a mod-r/m byte+offset for the following addressing scheme's [rm]
* disp8[rm] disp32[rm]
*
* @param rm
* @param disp
* @param reg
*/
private final void writeModRM(int rm, int disp, int reg) {
if ((rm < 0) || (rm > 7)) {
throw new IllegalArgumentException("rm");
}
if ((reg < 0) || (reg > 7)) {
throw new IllegalArgumentException("reg");
}
if (rm == X86Register.ESP.getNr()) {
if (disp == 0) { //TODO review wrt. writeLEA(GPR dstReg, GPR srcReg, int disp) todos
write8(0x00 | (reg << 3) | rm);
write8(0x24);
} else if (isByte(disp)) {
write8(0x40 | (reg << 3) | rm);
write8(0x24);
write8(disp);
} else {
write8(0x80 | (reg << 3) | rm);
write8(0x24);
write32(disp);
}
} else {
if ((disp == 0) && (rm != X86Register.EBP.getNr())) {
write8(0x00 | (reg << 3) | rm);
} else if (isByte(disp)) {
write8(0x40 | (reg << 3) | rm);
write8(disp);
} else {
write8(0x80 | (reg << 3) | rm);
write32(disp);
}
}
}
/**
* Write a 1-byte instruction followed by a mod-r/m byte+offset for the
* following addressing scheme's [rm] disp8[rm] disp32[rm]
*
* @param opcode
* @param rm
* @param disp
* @param reg
*/
private final void write1bOpcodeModRM(int opcode, int operandSize, GPR rm,
int disp, int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode);
writeModRM(rm.getNr() & 7, disp, reg & 7);
}
/**
* Write a 2-byte instruction followed by a mod-r/m byte+offset for the
* following addressing scheme's [rm] disp8[rm] disp32[rm]
*
* @param opcode1
* @param opcode2
* @param operandSize
* @param rm
* @param disp
* @param reg
*/
private final void write2bOpcodeModRM(int opcode1, int opcode2,
int operandSize, GPR rm, int disp, int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode1);
write8(opcode2);
writeModRM(rm.getNr() & 7, disp, reg & 7);
}
/**
* Write a 2-byte instruction followed by a mod-r/m byte+offset for the
* following addressing scheme's [rm] disp8[rm] disp32[rm]
*
* @param opcode1
* @param opcode2
* @param opcode3
* @param operandSize
* @param rm
* @param disp
* @param reg
*/
private final void write3bOpcodeModRM(int opcode1, int opcode2,
int opcode3, int operandSize, GPR rm, int disp, int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode1);
write8(opcode2);
write8(opcode3);
writeModRM(rm.getNr() & 7, disp, reg & 7);
}
/**
* Write a 1-byte instruction followed by a mod-r/m byte+offset for the
* following addressing scheme's disp32
*
* @param opcode
* @param disp
* @param reg
*/
private final void write1bOpcodeModMem(int opcode, int operandSize,
int disp, int reg) {
writeModRMRREXPrefix(operandSize, null, reg);
write8(opcode);
writeModRM(5, disp, reg & 7);
}
/**
* Write a mod-r/m byte+offset+scale+index+base for the following addressing
* scheme's [rm] disp8[rm] disp32[rm] To create
* <code>[index*scale+disp]</code> code, set base to -1.
*
* @param base
* @param disp
* @param reg
* @param scale
* @param index
*/
private final void writeModRMSib(int base, int disp, int reg, int scale,
int index) {
if ((base < -1) || (base > 7))
throw new IllegalArgumentException("base");
if ((reg < 0) || (reg > 7))
throw new IllegalArgumentException("reg");
if ((index < 0) || (index > 7))
throw new IllegalArgumentException("index");
switch (scale) {
case 1:
scale = 0;
break;
case 2:
scale = 1;
break;
case 4:
scale = 2;
break;
case 8:
scale = 3;
break;
default:
throw new IllegalArgumentException("scale");
}
if (base == -1) {
write8(0x00 | (reg << 3) | 4);
write8((scale << 6) | (index << 3) | 5);
write32(disp);
} else if ((disp == 0) && (base != X86Register.EBP.getNr())) {
write8(0x00 | (reg << 3) | 4);
write8((scale << 6) | (index << 3) | base);
} else if (isByte(disp)) {
write8(0x40 | (reg << 3) | 4);
write8((scale << 6) | (index << 3) | base);
write8(disp);
} else {
write8(0x80 | (reg << 3) | 4);
write8((scale << 6) | (index << 3) | base);
write32(disp);
}
}
/**
* Write a 1-byte instruction followed by a mod-r/m byte+offset for the
* following addressing scheme's [rm] disp8[rm] disp32[rm]
*
* @param opcode
* @param base
* @param disp
* @param reg
* @param scale
* @param index
*/
private final void write1bOpcodeModRMSib(int opcode, int operandSize,
GPR base, int disp, int reg, int scale, GPR index) {
testSize(base, mode.getSize());
testSize(index, mode.getSize());
writeModRMSibREXPrefix(operandSize, base, reg, index);
write8(opcode);
writeModRMSib(base.getNr() & 7, disp, reg & 7, scale, index.getNr() & 7);
}
/**
* Write a mod-r/m byte for the following addressing scheme rm
*
* @param rm
* @param reg
*/
private final void writeModRR(int rm, int reg) {
if ((rm < 0) || (rm > 7))
throw new IllegalArgumentException("rm");
if ((reg < 0) || (reg > 7))
throw new IllegalArgumentException("reg");
write8(0xc0 | (reg << 3) | rm);
}
/**
* Write a 1-byte instruction followed by a mod-r/m byte for the following
* addressing scheme rm
*
* @param opcode
* @param operandSize Size of the operands ({@link X86Constants}.BITSxxx)
* @param rm
* @param reg
*/
private final void write1bOpcodeModRR(int opcode, int operandSize, GPR rm,
int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode);
writeModRR(rm.getNr() & 7, reg & 7);
}
/**
* Write a 2-byte instruction followed by a mod-r/m byte for the following
* addressing scheme rm
*
* @param opcode1
* @param opcode2
* @param operandSize
* @param rm
* @param reg
*/
private final void write2bOpcodeModRR(int opcode1, int opcode2,
int operandSize, GPR rm, int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode1);
write8(opcode2);
writeModRR(rm.getNr() & 7, reg & 7);
}
/**
* Write a 3-byte instruction followed by a mod-r/m byte for the following
* addressing scheme rm
*
* @param opcode1
* @param opcode2
* @param opcode3
* @param operandSize
* @param rm
* @param reg
*/
private final void write3bOpcodeModRR(int opcode1, int opcode2,
int opcode3, int operandSize, X86Register rm, int reg) {
writeModRMRREXPrefix(operandSize, rm, reg);
write8(opcode1);
write8(opcode2);
write8(opcode3);
writeModRR(rm.getNr() & 7, reg & 7);
}
private void writeModRR_MMX(int opcode, X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
write8(0x0F);
write8(opcode);
writeModRR(srcMmx.getNr() & 7, dstMmx.getNr() & 7);
}
/**
* Create a mov [dstReg:dstDisp], <srcReg>
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeMOV(SR dstReg, int dstDisp, GPR srcReg) {
testSize(srcReg, mode.getSize());
writeSegPrefix(dstReg);
if (srcReg == GPR.EAX) {
write8(0xA3);
write32(dstDisp);
} else {
write8(0x89);
write8(0x05 | srcReg.getNr() << 3);
write32(dstDisp);
}
}
/**
* Create a mov [dstReg+dstDisp], <srcReg>
*
* @param operandSize
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeMOV(int operandSize, GPR dstReg, int dstDisp,
GPR srcReg) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
testSize(srcReg, BITS8 | BITS16 | BITS32 | BITS64);
//TODO review
testDst(dstReg, dstDisp);
final int opcode;
switch (operandSize) {
case X86Constants.BITS8:
testSuitableForBits8(srcReg);
opcode = 0x88;
break;
case X86Constants.BITS16:
opcode = 0x89;
write8(OSIZE_PREFIX);
break;
case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x89;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write1bOpcodeModRM(opcode, operandSize, dstReg, dstDisp, srcReg.getNr());
}
/**
* Create a mov <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
*/
public final void writeMOV(CRX dstReg, GPR srcReg) {
testSize(srcReg, mode.getSize());
write8(CRX_PREFIX);
write8(0x22);
writeModRR(srcReg.getNr() & 7, dstReg.getNr() & 7);
}
/**
* Create a mov <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
*/
public final void writeMOV(GPR dstReg, CRX srcReg) {
testSize(dstReg, mode.getSize());
write8(CRX_PREFIX);
write8(0x20);
writeModRR(dstReg.getNr() & 7, srcReg.getNr() & 7);
}
/**
* Create a mov <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
*/
public final void writeMOV(SR dstReg, GPR srcReg) {
if (X86Register.CS.equals(dstReg))
throw new IllegalArgumentException("Cannot MOV to CS");
testSize(srcReg, BITS16 | BITS32);
if (srcReg.getSize() == BITS16) {
writePrefix(X86Constants.OSIZE_PREFIX);
}
write8(0x8E);
writeModRR(srcReg.getNr() & 7, dstReg.getNr() & 7);
}
/**
* Create a mov <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
*/
public final void writeMOV(GPR dstReg, SR srcReg) {
testSize(dstReg, BITS16 | BITS32);
writePrefix(X86Constants.OSIZE_PREFIX);
write8(0x8C);
writeModRR(dstReg.getNr() & 7, srcReg.getNr() & 7);
}
/**
* Create a mov <dstReg>, <srcReg>
*
* @param operandSize
* @param dstReg
* @param srcReg
*/
public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
testSize(srcReg, BITS8 | BITS16 | BITS32 | BITS64);
//TODO review
final int opcode;
switch (operandSize) {
case X86Constants.BITS8:
testSuitableForBits8(dstReg);
testSuitableForBits8(srcReg);
opcode = 0x88;
break;
case X86Constants.BITS16:
opcode = 0x89;
write8(OSIZE_PREFIX);
break;
case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x89;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write1bOpcodeModRR(opcode, operandSize, dstReg, srcReg.getNr());
}
/**
* Create a mov dstReg, [srcReg:srcDisp]
*
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public final void writeMOV(GPR dstReg, SR srcReg, int srcDisp) {
testSize(dstReg, mode.getSize());
writeSegPrefix(srcReg);
if (dstReg == GPR.EAX) {
write8(0xA1);
write32(srcDisp);
} else {
write8(0x8b);
write8(0x05 | dstReg.getNr() << 3);
write32(srcDisp);
}
}
/**
* Create a mov dstReg, [srcReg+srcDisp]
*
* @param operandSize
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg,
int srcDisp) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
testSize(srcReg, mode.getSize());
//TODO review
final int opcode;
switch (operandSize) {
case X86Constants.BITS8:
testSuitableForBits8(dstReg);
opcode = 0x8a;
break;
case X86Constants.BITS16:
opcode = 0x8b;
write8(OSIZE_PREFIX);
break;
case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x8b;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write1bOpcodeModRM(opcode, operandSize, srcReg, srcDisp, dstReg.getNr());
}
/**
* Create a mov [dstReg+dstIdxReg*scale+dstDisp], <srcReg>
*
* @param operandSize
* @param dstReg
* @param dstIdxReg
* @param scale
* @param dstDisp
* @param srcReg
*/
public final void writeMOV(int operandSize, GPR dstReg, GPR dstIdxReg,
int scale, int dstDisp, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
testSize(dstIdxReg, mode.getSize());
final int opcode;
switch (operandSize) {
case X86Constants.BITS8:
testSuitableForBits8(srcReg);
opcode = 0x88;
break;
case X86Constants.BITS16:
opcode = 0x89;
write8(OSIZE_PREFIX);
break;
case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x89;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write1bOpcodeModRMSib(opcode, operandSize, dstReg, dstDisp, srcReg
.getNr(), scale, dstIdxReg);
}
/**
* Create a mov dstReg, [srcReg+srcIdxReg*scale+srcDisp]
*
* @param operandSize
* @param dstReg
* @param srcReg
* @param srcIdxReg
* @param scale
* @param srcDisp
*/
public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg,
GPR srcIdxReg, int scale, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
testSize(srcIdxReg, mode.getSize());
final int opcode;
switch (operandSize) {
case X86Constants.BITS8:
testSuitableForBits8(dstReg);
opcode = 0x8a;
break;
case X86Constants.BITS16:
opcode = 0x8b;
write8(OSIZE_PREFIX);
break;
case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x8b;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write1bOpcodeModRMSib(opcode, operandSize, srcReg, srcDisp, dstReg
.getNr(), scale, srcIdxReg);
}
/**
* @param dstReg
* @param srcDisp
*/
public final void writeMOV(GPR dstReg, int srcDisp) {
testSize(dstReg, BITS8 | BITS16 | BITS32);
int size = dstReg.getSize();
//TODO review
if (dstReg == GPR.EAX) {
write8(0xA1);
write32(srcDisp);
} else if (size == BITS32) {
write8(0x8b);
write8(dstReg.getNr() << 3 | 5);
write32(srcDisp);
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write8(0x8b);
write8(dstReg.getNr() << 3 | 5);
write32(srcDisp);
} else if (size == BITS8) {
write8(0x8a);
write8(dstReg.getNr() << 3 | 5);
write32(srcDisp);
}
}
/**
* @param dstDisp
* @param srcReg
*/
public final void writeMOV(int dstDisp, GPR srcReg) {
testSize(srcReg, BITS8 | BITS16 | BITS32);
int size = srcReg.getSize();
//TODO review
if (srcReg == GPR.AL) {
write8(0xA2);
write32(dstDisp);
} else if (srcReg == GPR.AX) {
write8(OSIZE_PREFIX);
write8(0xA3);
write32(dstDisp);
} else if (srcReg == GPR.EAX) {
write8(0xA3);
write32(dstDisp);
} else if (size == BITS32) {
write8(0x89);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write8(0x89);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS8) {
write8(0x88);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
}
}
/**
* @param operandSize
* @param dstDisp
* @param imm32
*/
public final void writeMOV_Const(int operandSize, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
//TODO review
if (operandSize == BITS32) {
write8(0xc7);
write8(5);
write32(dstDisp);
write32(imm32);
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
write8(0xc7);
write8(5);
write32(dstDisp);
write16(imm32);
} else if (operandSize == BITS8) {
write8(0xc6);
write8(5);
write32(dstDisp);
write8(imm32);
}
}
/**
* Create a MOV reg,imm32 or MOV reg,imm64
*
* @param dstReg
* @param imm32
*/
public final void writeMOV_Const(GPR dstReg, int imm32) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
if (dstReg.getSize() == BITS32) {
write1bOpcodeReg(0xB8, dstReg);
write32(imm32);
} else if (dstReg.getSize() == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeReg(0xB8, dstReg);
write16(imm32);
} else if (dstReg.getSize() == BITS8) {
write1bOpcodeReg(0xB0, dstReg);
write8(imm32);
} else {
writeMOV_Const(dstReg, (long) imm32);
}
}
/**
* Create a MOV reg,imm64 depending on the reg size. Only valid in 64-bit
* mode.
*
* @param dstReg
* @param imm64
* @throws InvalidOpcodeException In 32-bit modes.
*/
public void writeMOV_Const(GPR dstReg, long imm64)
throws InvalidOpcodeException {
if (!code64) {
throw new InvalidOpcodeException();
}
testSize(dstReg, BITS64);
write1bOpcodeReg(0xB8, dstReg);
write64(imm64);
}
/**
* Create a mov [destReg:destDisp], imm32
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public final void writeMOV_Const(int operandSize, SR dstReg,
int dstDisp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
write8(0xC7);
write8(0x05);
write32(dstDisp);
write32(imm32);
}
/**
* Create a mov [destReg+destDisp], imm32
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public final void writeMOV_Const(int operandSize, GPR dstReg,
int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
testOperandSize(operandSize, BITS8 | BITS16 | BITS32 | BITS64);
if (operandSize == BITS8) {
write1bOpcodeModRM(0xC6, operandSize, dstReg, dstDisp, 0);
write8(imm32);
} else {
if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
}
write1bOpcodeModRM(0xC7, operandSize, dstReg, dstDisp, 0);
if (operandSize == BITS16) {
write16(imm32);
} else {
write32(imm32);
}
}
}
/**
* Create a mov reg, label
*
* @param dstReg
* @param label
*/
public final void writeMOV_Const(GPR dstReg, Object label) {
testSize(dstReg, mode.getSize());
testOperandSize(dstReg.getSize(), mode.getSize());
write1bOpcodeReg(0xB8, dstReg);
writeObjectRef(label, 0, false);
}
/**
* Create a mov size [destReg+dstIdxReg*scale+destDisp], imm32
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeMOV_Const(int operandSize, GPR dstReg, GPR dstIdxReg,
int scale, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
testSize(dstIdxReg, mode.getSize());
write1bOpcodeModRMSib(0xC7, operandSize, dstReg, dstDisp, 0, scale,
dstIdxReg);
write32(imm32);
}
//todo 64 bits support
/**
* @param operandSize
* @param dstMmx
* @param srcReg
* @param srcDisp
*/
public void writeMOVD(int operandSize, MMX dstMmx, GPR srcReg, int srcDisp) {
testSize(srcReg, mode.getSize());
final int opcode;
switch (operandSize) {
case X86Constants.BITS32:
// case X86Constants.BITS64:
opcode = 0x6E;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write2bOpcodeModRM(0x0F, opcode, operandSize, srcReg, srcDisp, dstMmx.getNr());
}
//todo 64 bits support
/**
* @param operandSize
* @param dstReg
* @param dstDisp
* @param srcMmx
*/
public void writeMOVD(int operandSize, X86Register.GPR dstReg, int dstDisp, X86Register.MMX srcMmx) {
testSize(dstReg, mode.getSize());
final int opcode;
switch (operandSize) {
case X86Constants.BITS32:
// case X86Constants.BITS64:
opcode = 0x7E;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write2bOpcodeModRM(0x0F, opcode, operandSize, dstReg, dstDisp, srcMmx.getNr());
}
//todo 64 bits support
/**
* @param dstMmx
* @param srcMmx
*/
public void writeMOVQ(X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
writeModRR_MMX(0x6F, dstMmx, srcMmx);
}
//todo 64 bits support
/**
* @param operandSize
* @param dstMmx
* @param srcReg
* @param srcDisp
*/
public void writeMOVQ(int operandSize, X86Register.MMX dstMmx, X86Register.GPR srcReg, int srcDisp) {
testSize(srcReg, mode.getSize());
final int opcode;
switch (operandSize) {
// case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x6F;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write8(0x0F);
write8(opcode);
writeModRM(srcReg.getNr() & 7, srcDisp, dstMmx.getNr() & 7);
}
//todo 64 bits support
/**
* @param operandSize
* @param dstMmx
* @param srcDisp
*/
public void writeMOVQ(int operandSize, X86Register.MMX dstMmx, int srcDisp) {
testOperandSize(mode.getSize(), X86Constants.BITS32);
final int opcode;
switch (operandSize) {
// case X86Constants.BITS32:
case X86Constants.BITS64:
opcode = 0x6F;
break;
default:
throw new IllegalArgumentException("Invalid operandSize "
+ operandSize);
}
write8(0x0F);
write8(opcode);
write8(dstMmx.getNr() << 3 | 5);
write32(srcDisp);
}
/**
* Create a movsb
*/
public void writeMOVSB() {
write8(0xA4);
}
/**
* Create a movsd
*/
public void writeMOVSD() {
write8(0xA5);
}
/**
* Create a movsd [dst+dstDisp],src
*
* @param dst
* @param src
*/
public void writeMOVSD(X86Register.GPR dst, int dstDisp, X86Register.XMM src) {
write3bOpcodeModRM(0xF2, 0x0F, 0x11, 0, dst, dstDisp, src.getNr());
}
/**
* Create a movsd dst,[src+srcDisp]
*
* @param dst
* @param src
*/
public void writeMOVSD(X86Register.XMM dst, X86Register.GPR src, int srcDisp) {
write3bOpcodeModRM(0xF2, 0x0F, 0x10, 0, src, srcDisp, dst.getNr());
}
/**
* Create a movsd dst,src
*
* @param dst
* @param src
*/
public void writeMOVSD(X86Register.XMM dst, X86Register.XMM src) {
write3bOpcodeModRR(0xF2, 0x0F, 0x10, 0, dst, src.getNr());
}
/**
* Create a movss [dst+dstDisp],src
*
* @param dst
* @param src
*/
public void writeMOVSS(X86Register.GPR dst, int dstDisp, X86Register.XMM src) {
write3bOpcodeModRM(0xF3, 0x0F, 0x11, 0, dst, dstDisp, src.getNr());
}
/**
* Create a movss dst,[src+srcDisp]
*
* @param dst
* @param src
*/
public void writeMOVSS(X86Register.XMM dst, X86Register.GPR src, int srcDisp) {
write3bOpcodeModRM(0xF3, 0x0F, 0x10, 0, src, srcDisp, dst.getNr());
}
/**
* Create a movss dst,src
*
* @param dst
* @param src
*/
public void writeMOVSS(X86Register.XMM dst, X86Register.XMM src) {
write3bOpcodeModRR(0xF3, 0x0F, 0x10, 0, dst, src.getNr());
}
/**
* Create a movsx <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
* @param srcSize
*/
public final void writeMOVSX(GPR dstReg, GPR srcReg, int srcSize) {
if (srcSize == X86Constants.BITS8) {
testSuitableForBits8(dstReg);
write2bOpcodeModRR(0x0F, 0xBE, dstReg.getSize(), srcReg, dstReg
.getNr());
} else if (srcSize == X86Constants.BITS16) {
write2bOpcodeModRR(0x0F, 0xBF, dstReg.getSize(), srcReg, dstReg
.getNr());
} else {
throw new IllegalArgumentException("Unknown srcSize " + srcSize);
}
}
public void writeMOVSX(GPR dstReg, GPR srcReg, int srcDisp, int srcSize) {
if (srcSize == X86Constants.BITS8) {
testSuitableForBits8(dstReg);
write2bOpcodeModRM(0x0F, 0xBE, dstReg.getSize(), srcReg, srcDisp,
dstReg.getNr());
} else if (srcSize == X86Constants.BITS16) {
write2bOpcodeModRM(0x0F, 0xBF, dstReg.getSize(), srcReg, srcDisp,
dstReg.getNr());
} else {
throw new IllegalArgumentException("Unknown srcSize " + srcSize);
}
}
/**
* Create a movsxd dstReg, srcReg. Sign extends the srcReg to dstReg. Only
* valid in 64-bit mode.
*
* @param dstReg
* @param srcReg
*/
public void writeMOVSXD(GPR64 dstReg, GPR32 srcReg)
throws InvalidOpcodeException {
if (!code64) {
throw new InvalidOpcodeException();
}
write1bOpcodeModRR(0x63, dstReg.getSize(), srcReg, dstReg.getNr());
}
/**
* Create a movsw
*/
public void writeMOVSW() {
if (mode.getSize() == X86Constants.BITS32) {
write8(OSIZE_PREFIX);
}
write8(0xA5);
}
/**
* Create a movzx <dstReg>, <srcReg>
*
* @param dstReg
* @param srcReg
* @param srcSize
*/
public final void writeMOVZX(GPR dstReg, GPR srcReg, int srcSize) {
if (srcSize == X86Constants.BITS8) {
testSuitableForBits8(dstReg);
write2bOpcodeModRR(0x0F, 0xB6, dstReg.getSize(), srcReg, dstReg
.getNr());
} else if (srcSize == X86Constants.BITS16) {
write2bOpcodeModRR(0x0F, 0xB7, dstReg.getSize(), srcReg, dstReg
.getNr());
} else {
throw new IllegalArgumentException("Unknown srcSize " + srcSize);
}
}
public void writeMOVZX(GPR dstReg, GPR srcReg, int srcDisp, int srcSize) {
if (srcSize == X86Constants.BITS8) {
testSuitableForBits8(dstReg);
write2bOpcodeModRM(0x0F, 0xB6, dstReg.getSize(), srcReg, srcDisp,
dstReg.getNr());
} else if (srcSize == X86Constants.BITS16) {
write2bOpcodeModRM(0x0F, 0xB7, dstReg.getSize(), srcReg, srcDisp,
dstReg.getNr());
} else {
throw new IllegalArgumentException("Unknown srcSize " + srcSize);
}
}
/**
* Create a mul eax, srcReg
*
* @param srcReg
*/
public final void writeMUL_EAX(GPR srcReg) {
write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 4);
}
/**
* Create a neg dstReg
*
* @param dstReg
*/
public final void writeNEG(GPR dstReg) {
testSize(dstReg, BITS32 | BITS64);
write1bOpcodeModRR(0xf7, dstReg.getSize(), dstReg, 3);
}
/**
* Create a neg dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeNEG(int operandSize, GPR dstReg, int dstDisp) {
testSize(dstReg, mode.getSize());
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRM(0xf7, operandSize, dstReg, dstDisp, 3);
}
/**
* Create a nop
*/
public final void writeNOP() {
write8(0x90);
}
/**
* Create a not dstReg
*
* @param dstReg
*/
public final void writeNOT(GPR dstReg) {
write1bOpcodeModRR(0xf7, dstReg.getSize(), dstReg, 2);
}
/**
* Create a not dword [dstReg+dstDisp]
*
* @param dstReg
* @param dstDisp
*/
public final void writeNOT(int operandSize, GPR dstReg, int dstDisp) {
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRM(0xf7, operandSize, dstReg, dstDisp, 2);
}
/**
* Create 32-bit reference to an absolute address like: dd label
*
* @param object
*/
public final void writeObjectRef(Object object) {
writeObjectRef(object, 0, false);
}
/**
* Create 32-bit reference to an absolute address like: dd label
*
* @param object
*/
public final void setObjectRef(int offset, Object object) {
setObjectRef(offset, object, 0, false);
}
/**
* Create 32-bit reference to an absolute address like: dd label
*
* @param object
* @param offset
* @param rawAddress If true, object is a raw address, not a normal object.
*/
private final void writeObjectRef(Object object, int offset,
boolean rawAddress) {
if (object == null) {
writeWord(offset);
} else if (rawAddress) {
if (mode.is32()) {
write32(resolver.addressOf32(object) + offset);
} else {
write64(resolver.addressOf64(object) + offset);
}
} else if ((resolver != null) && (!(object instanceof Label))) {
if (mode.is32()) {
write32(resolver.addressOf32(object) + offset);
} else {
write64(resolver.addressOf64(object) + offset);
}
} else {
final X86ObjectRef ref = (X86ObjectRef) getObjectRef(object);
if (ref.isResolved()) {
try {
//System.out.println("Resolved offset " + ref.getOffset());
writeWord(ref.getOffset() + baseAddr + offset);
} catch (UnresolvedObjectRefException e) {
throw new RuntimeException(e);
}
} else {
//System.out.println("Unresolved");
ref.addUnresolvedLink(m_used, getWordSize());
writeWord(-(baseAddr + offset));
}
}
}
/**
* Create 32-bit reference to an absolute address like: dd label
*
* @param object
* @param offset
* @param rawAddress If true, object is a raw address, not a normal object.
*/
private final void setObjectRef(int dataOffset, Object object, int offset,
boolean rawAddress) {
if (object == null) {
setWord(dataOffset, offset);
} else if (rawAddress) {
if (mode.is32()) {
set32(dataOffset, resolver.addressOf32(object) + offset);
} else {
set64(dataOffset, resolver.addressOf64(object) + offset);
}
} else if ((resolver != null) && (!(object instanceof Label))) {
if (mode.is32()) {
set32(dataOffset, resolver.addressOf32(object) + offset);
} else {
set64(dataOffset, resolver.addressOf64(object) + offset);
}
} else {
final X86ObjectRef ref = (X86ObjectRef) getObjectRef(object);
if (ref.isResolved()) {
try {
//System.out.println("Resolved offset " + ref.getOffset());
setWord(dataOffset, ref.getOffset() + baseAddr + offset);
} catch (UnresolvedObjectRefException e) {
throw new RuntimeException(e);
}
} else {
//System.out.println("Unresolved");
ref.addUnresolvedLink(dataOffset, getWordSize());
setWord(dataOffset, -(baseAddr + offset));
}
}
}
/**
* @param dstReg
* @param imm32
*/
public void writeOR(GPR dstReg, int imm32) {
testSize(dstReg, BITS8 | BITS16 | BITS32 | BITS64);
int size = dstReg.getSize();
if (dstReg == GPR.AL) {
write8(0x0C);
write8(imm32);
} else if (dstReg == GPR.EAX && !isByte(imm32)) {
write8(0x0D);
write32(imm32);
} else if ((size & (BITS32 | BITS64)) == size) {
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 1);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 1);
write32(imm32);
}
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 1);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 1);
write16(imm32);
}
} else if (size == BITS8) {
write1bOpcodeModRR(0x80, dstReg.getSize(), dstReg, 1);
write8(imm32);
}
}
/**
* @param operandSize
* @param dstDisp
* @param imm32
*/
public void writeOR(int operandSize, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
//TODO review
if (operandSize == BITS32) {
write8(0x81);
write8((1 << 3) | 5);
write32(dstDisp);
write32(imm32);
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
write8(0x81);
write8((1 << 3) | 5);
write32(dstDisp);
write16(imm32);
} else if (operandSize == BITS8) {
write8(0x80);
write8((1 << 3) | 5);
write32(dstDisp);
write8(imm32);
}
}
/**
* @param operandSize
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeOR(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS16 | BITS32);
if (operandSize == BITS32) {
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 1);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 1);
write32(imm32);
}
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 1);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 1);
write16(imm32);
}
}
}
/**
* @param operandSize
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeOR(int operandSize, SR dstReg, int dstDisp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(dstReg);
//todo review
if (isUByte(imm32)) {
write8(0x83);
write8(0x0D);
write32(dstDisp);
write8(imm32);
} else {
write8(0x81);
write8(0x0D);
write32(dstDisp);
write32(imm32);
}
}
/**
* Create a OR [dstReg+dstDisp], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeOR(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, BITS8 | BITS16 | BITS32 | BITS64);
int size = srcReg.getSize();
if ((size & (BITS32 | BITS64)) == size) {
write1bOpcodeModRM(0x09, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRM(0x09, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS8) {
write1bOpcodeModRM(0x08, size, dstReg, dstDisp, srcReg.getNr());
}
}
/**
* Create a OR dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeOR(GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRR(0x09, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* Create a OR dstReg, [srcReg+srcDisp]
*
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeOR(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRM(0x0B, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
public void writeOUT(int operandSize) {
if (operandSize == X86Constants.BITS8) {
write8(0xEE);
} else if (operandSize == X86Constants.BITS16) {
write8(X86Constants.OSIZE_PREFIX);
write8(0xEF);
} else if (operandSize == X86Constants.BITS32) {
write8(0xEF);
} else {
throw new IllegalArgumentException("Invalid operand size for OUT: " + operandSize);
}
}
public void writeOUT(int operandSize, int imm8) {
if (operandSize == X86Constants.BITS8) {
write8(0xE6);
write8(imm8);
} else if (operandSize == X86Constants.BITS16) {
write8(X86Constants.OSIZE_PREFIX);
write8(0xE7);
write8(imm8);
} else if (operandSize == X86Constants.BITS32) {
write8(0xE7);
write8(imm8);
} else {
throw new IllegalArgumentException("Invalid operand size for OUT: " + operandSize);
}
}
public void writePACKUSWB(MMX dstMmx, MMX srcMmx) {
writeModRR_MMX(0x67, dstMmx, srcMmx);
}
public void writePADDW(X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
writeModRR_MMX(0xFD, dstMmx, srcMmx);
}
public void writePAND(X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
writeModRR_MMX(0xDB, dstMmx, srcMmx);
}
public void writePCMPGTW(X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
writeModRR_MMX(0x65, dstMmx, srcMmx);
}
public void writePMULLW(X86Register.MMX dstMmx, X86Register.MMX srcMmx) {
writeModRR_MMX(0xD5, dstMmx, srcMmx);
}
/**
* Create a pop reg32
*
* @param dstReg
*/
public final void writePOP(GPR dstReg) {
testSize(dstReg, BITS32 | BITS64);
write1bOpcodeReg(0x58, dstReg);
}
/**
* Create a pop sreg
*
* @param dstReg
*/
public final void writePOP(SR dstReg) {
if (X86Register.ES.equals(dstReg)) {
write8(0x07);
} else if (X86Register.DS.equals(dstReg)) {
write8(0x1F);
} else if (X86Register.FS.equals(dstReg)) {
write8(0x0F);
write8(0xA1);
} else if (X86Register.GS.equals(dstReg)) {
write8(0x0F);
write8(0xA9);
} else if (X86Register.SS.equals(dstReg)) {
write8(0x17);
} else if (X86Register.CS.equals(dstReg)) {
throw new IllegalArgumentException("Cannot POP to CS");
} else {
throw new IllegalArgumentException("Unknown segment register: " + dstReg);
}
}
/**
* Create a pop dword [reg32+disp]
*
* @param dstReg
* @param dstDisp
*/
public final void writePOP(GPR dstReg, int dstDisp) {
testSize(dstReg, mode.getSize());
// POP has no encoding for 32-bit in 64-bit mode, so give
// operand size 0 to avoid a REX prefix.
write1bOpcodeModRM(0x8f, 0, dstReg, dstDisp, 0);
}
public void writePOPA() {
if (code64) {
throw new InvalidOpcodeException();
}
write8(0x61);
}
public void writePOPF() {
write8(0x9D);
}
public void writePrefix(int prefix) {
write8(prefix);
}
public void writePSHUFW(MMX dstMmx, MMX srcMmx, int imm8) {
writeModRR_MMX(0x70, dstMmx, srcMmx);
write8(imm8);
}
public void writePSRLW(X86Register.MMX mmx, int imm8) {
write8(0x0F);
write8(0x71);
writeModRR(mmx.getNr() & 7, 2);
write8(imm8);
}
public void writePSUBW(MMX dstMmx, MMX srcMmx) {
writeModRR_MMX(0xF9, dstMmx, srcMmx);
}
public void writePUNPCKLBW(MMX dstMmx, MMX srcMmx) {
writeModRR_MMX(0x60, dstMmx, srcMmx);
}
/**
* Create a push dword imm32
*
* @param imm32
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(int imm32) {
final int rc = m_used;
if (isByte(imm32)) {
write8(0x6A); // PUSH imm8
write8(imm32);
} else {
write8(0x68); // PUSH imm32
write32(imm32);
}
return rc;
}
/**
* Create a push srcReg
*
* @param srcReg
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(GPR srcReg) {
testSize(srcReg, BITS32 | BITS64);
final int rc = m_used;
write1bOpcodeReg(0x50, srcReg);
return rc;
}
/**
* Create a push srcReg
*
* @param srcReg
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(SR srcReg) {
final int rc = m_used;
if (X86Register.ES.equals(srcReg)) {
write8(0x06);
} else if (X86Register.DS.equals(srcReg)) {
write8(0x1E);
} else if (X86Register.FS.equals(srcReg)) {
write8(0x0F);
write8(0xA0);
} else if (X86Register.GS.equals(srcReg)) {
write8(0x0F);
write8(0xA8);
} else if (X86Register.SS.equals(srcReg)) {
write8(0x16);
} else if (X86Register.CS.equals(srcReg)) {
write8(0x0E);
} else {
throw new IllegalArgumentException("Unknown segment register: " + srcReg);
}
return rc;
}
/**
* Create a push d/qword [srcReg+srcDisp]
*
* @param srcReg
* @param srcDisp
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(GPR srcReg, int srcDisp) {
testSize(srcReg, mode.getSize());
// PUSH has not encoding for 32-bit in 64-bit mode, so give
// operand size 0 to avoid a REX prefix.
final int rc = m_used;
write1bOpcodeModRM(0xFF, 0, srcReg, srcDisp, 6);
return rc;
}
/**
* Create a push d/qword [srcReg+srcDisp]
*
* @param sr
* @param srcDisp
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(SR sr, int srcDisp) {
testOperandSize(4, mode.getSize());
// PUSH has not encoding for 32-bit in 64-bit mode, so give
// operand size 0 to avoid a REX prefix.
final int rc = m_used;
writeSegPrefix(sr);
write8(0xFF);
write8(0x35);
write32(srcDisp);
return rc;
}
/**
* Create a push d/qword [baseReg+indexReg*scale+disp]
*
* @param srcBaseReg
* @param srcIndexReg
* @param srcScale
* @param srcDisp
* @return The ofset of the start of the instruction.
*/
public final int writePUSH(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
int srcDisp) {
testSize(srcBaseReg, mode.getSize());
testSize(srcIndexReg, mode.getSize());
// PUSH has not encoding for 32-bit in 64-bit mode, so give
// operand size 0 to avoid a REX prefix.
final int rc = m_used;
write1bOpcodeModRMSib(0xFF, 0, srcBaseReg, srcDisp, 6, srcScale,
srcIndexReg);
return rc;
}
/**
* Create a push dword <object>
*
* @param objRef
* @return The offset of the start of the instruction.
*/
public final int writePUSH_Const(Object objRef) {
if (code64) {
throw new InvalidOpcodeException("Not support in 64-bit mode");
}
final int rc = m_used;
write8(0x68); // PUSH imm32
writeObjectRef(objRef, 0, false);
return rc;
}
public void writePUSHA() {
if (code64) {
throw new InvalidOpcodeException();
}
write8(0x60);
}
public void writePUSHF() {
write8(0x9C);
}
public void writePXOR(MMX dstMmx, MMX srcMmx) {
writeModRR_MMX(0xEF, dstMmx, srcMmx);
}
public void writeRDTSC() {
write8(0x0F);
write8(0x31);
}
/**
* Create 32-bit offset relative to the current (after this offset) offset.
*
* @param object
*/
public final void writeRelativeObjectRef(Label object) {
if (object == null) {
throw new NullPointerException();
}
final int ofs = m_used + 4;
final X86ObjectRef ref = (X86ObjectRef) getObjectRef(object);
ref.setRelJump();
if (ref.isResolved()) {
try {
write32(ref.getOffset() - ofs);
} catch (UnresolvedObjectRefException ex) {
throw new RuntimeException(ex);
}
} else {
ref.addUnresolvedLink(m_used, 4);
write32(ofs);
}
}
/**
* Create a ret near to caller
*/
public final void writeRET() {
write8(0xc3);
}
/**
* Create a ret imm16 near to caller
*
* @param imm16
*/
public final void writeRET(int imm16) {
write8(0xc2);
write16(imm16);
}
/**
* Create a sahf
*/
public final void writeSAHF() {
if (code64) {
throw new InvalidOpcodeException();
}
write8(0x9e);
}
/**
* Create a SAL dstReg,imm8
*
* @param dstReg
* @param imm8
*/
public final void writeSAL(GPR dstReg, int imm8) {
write1bOpcodeModRR(0xc1, dstReg.getSize(), dstReg, 4);
write8(imm8);
}
/**
* @param dstReg
* @param dstDisp
* @param imm8
*/
public void writeSAL(int operandSize, GPR dstReg, int dstDisp, int imm8) {
write1bOpcodeModRM(0xc1, operandSize, dstReg, dstDisp, 4);
write8(imm8);
}
/**
* Create a SAL dstReg,cl
*
* @param dstReg
*/
public final void writeSAL_CL(GPR dstReg) {
write1bOpcodeModRR(0xd3, dstReg.getSize(), dstReg, 4);
}
/**
* @param dstReg
* @param dstDisp
*/
public void writeSAL_CL(int operandSize, GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xd3, operandSize, dstReg, dstDisp, 4);
}
/**
* Create a SAR dstReg,imm8
*
* @param dstReg
* @param imm8
*/
public final void writeSAR(GPR dstReg, int imm8) {
write1bOpcodeModRR(0xc1, dstReg.getSize(), dstReg, 7);
write8(imm8);
}
/**
* @param dstReg
* @param dstDisp
* @param imm8
*/
public void writeSAR(int operandSize, GPR dstReg, int dstDisp, int imm8) {
write1bOpcodeModRM(0xc1, operandSize, dstReg, dstDisp, 7);
write8(imm8);
}
/**
* Create a SAR dstReg,cl
*
* @param dstReg
*/
public final void writeSAR_CL(GPR dstReg) {
write1bOpcodeModRR(0xd3, dstReg.getSize(), dstReg, 7);
}
/**
* @param dstReg
* @param dstDisp
*/
public void writeSAR_CL(int operandSize, GPR dstReg, int dstDisp) {
write1bOpcodeModRM(0xd3, operandSize, dstReg, dstDisp, 7);
}
/**
* Create a SBB dstReg, imm32
*
* @param dstReg
* @param imm32
*/
public void writeSBB(GPR dstReg, int imm32) {
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 3);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 3);
write32(imm32);
}
}
/**
* Create a SBB dword [dstReg+dstDisp], <imm32>
*
* @param dstReg
* @param dstDisp
* @param imm32
*/
public final void writeSBB(int operandSize, GPR dstReg, int dstDisp,
int imm32) {
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 3);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 3);
write32(imm32);
}
}
/**
* Create a SBB [dstReg+dstDisp], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeSBB(GPR dstReg, int dstDisp, GPR srcReg) {
write1bOpcodeModRM(0x19, srcReg.getSize(), dstReg, dstDisp, srcReg
.getNr());
}
/**
* Create a SBB dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeSBB(GPR dstReg, GPR srcReg) {
write1bOpcodeModRR(0x19, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeSBB(GPR dstReg, GPR srcReg, int srcDisp) {
write1bOpcodeModRM(0x1B, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
private final void writeSegPrefix(SR reg) {
if (reg.equals(DS)) {
write8(0x3e);
} else if (reg.equals(ES)) {
write8(0x26);
} else if (reg.equals(FS)) {
write8(0x64);
} else if (reg.equals(GS)) {
write8(0x65);
} else if (reg.equals(SS)) {
write8(0x36);
} else if (reg.equals(CS)) {
write8(0x2e);
} else {
throw new IllegalArgumentException("Unsopported segment register: " + reg);
}
}
/**
* Create a SETcc dstReg
*
* @param dstReg
* @param cc
*/
public void writeSETCC(GPR dstReg, int cc) {
testSuitableForBits8(dstReg);
// No change in 64-bit encoding, so give operand size 0 to
// avoid a REX prefix.
write2bOpcodeModRR(0x0F, 0x90 + (cc & 0x0f), 0, dstReg, 0);
}
/**
* Create a SHL dstReg,imm8
*
* @param dstReg
* @param imm8
*/
public final void writeSHL(GPR dstReg, int imm8) {
testSize(dstReg, mode.getSize());
if (imm8 == 1) {
write1bOpcodeModRR(0xd1, dstReg.getSize(), dstReg, 4);
} else {
write1bOpcodeModRR(0xc1, dstReg.getSize(), dstReg, 4);
write8(imm8);
}
}
public void writeSHL(int operandSize, GPR dstReg, int dstDisp, int imm8) {
testSize(dstReg, mode.getSize());
write1bOpcodeModRM(0xc1, operandSize, dstReg, dstDisp, 4);
write8(imm8);
}
/**
* Create a SHL dstReg,cl
*
* @param dstReg
*/
public final void writeSHL_CL(GPR dstReg) {
testSize(dstReg, mode.getSize());
write1bOpcodeModRR(0xd3, dstReg.getSize(), dstReg, 4);
}
public void writeSHL_CL(int operandSize, GPR dstReg, int dstDisp) {
testSize(dstReg, mode.getSize());
write1bOpcodeModRM(0xd3, operandSize, dstReg, dstDisp, 4);
}
/**
* Create a SHLD dstReg,srcReg,cl
*
* @param dstReg
* @param srcReg
*/
public final void writeSHLD_CL(GPR dstReg, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write2bOpcodeModRR(0x0F, 0xa5, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* Create a SHL dstReg,imm8
*
* @param dstReg
* @param imm8
*/
public final void writeSHR(GPR dstReg, int imm8) {
testSize(dstReg, BITS32 | BITS64);
write1bOpcodeModRR(0xc1, dstReg.getSize(), dstReg, 5);
write8(imm8);
}
/**
* @param dstReg
* @param dstDisp
* @param imm8
*/
public void writeSHR(int operandSize, GPR dstReg, int dstDisp, int imm8) {
testSize(dstReg, mode.getSize());
write1bOpcodeModRM(0xc1, operandSize, dstReg, dstDisp, 5);
write8(imm8);
}
/**
* Create a SHR dstReg,cl
*
* @param dstReg
*/
public final void writeSHR_CL(GPR dstReg) {
testSize(dstReg, BITS32 | BITS64);
write1bOpcodeModRR(0xd3, dstReg.getSize(), dstReg, 5);
}
/**
* @param dstReg
* @param dstDisp
*/
public void writeSHR_CL(int operandSize, GPR dstReg, int dstDisp) {
testSize(dstReg, mode.getSize());
write1bOpcodeModRM(0xd3, operandSize, dstReg, dstDisp, 5);
}
/**
* Create a SHRD dstReg,srcReg,cl
*
* @param dstReg
* @param srcReg
*/
public final void writeSHRD_CL(GPR dstReg, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write2bOpcodeModRR(0x0F, 0xad, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
*
*/
public void writeSTD() {
write8(0xFD);
}
/**
*
*/
public void writeSTI() {
write8(0xFB);
}
/**
* Create a stmxcsr dword [srcReg+disp]
*
* @param srcReg
* @param disp
*/
public final void writeSTMXCSR(GPR srcReg, int disp) {
write8(0x0f);
write8(0xae);
writeModRM(srcReg.getNr() & 7, disp, 3);
}
/**
*
*/
public void writeSTOSB() {
write8(0xAA);
}
/**
*
*/
public void writeSTOSD() {
write8(0xAB);
}
/**
*
*/
public void writeSTOSQ() {
write8(REX_W_PREFIX);
write8(0xAB);
}
/**
*
*/
public void writeSTOSW() {
write8(OSIZE_PREFIX);
write8(0xAB);
}
/**
* Create a SUB reg, imm32
*
* @param reg
* @param imm32
*/
public final void writeSUB(GPR reg, int imm32) {
testSize(reg, BITS32 | BITS64);
if (isByte(imm32)) {
write1bOpcodeModRR(0x83, reg.getSize(), reg, 5);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, reg.getSize(), reg, 5);
write32(imm32);
}
}
/**
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeSUB(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 5);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 5);
write32(imm32);
}
}
/**
* Create a SUB [dstDisp], <srcReg>
*
* @param dstDisp
* @param srcReg
*/
public final void writeSUB(int dstDisp, GPR srcReg) {
testSize(srcReg, BITS8 | BITS16 | BITS32);
int size = srcReg.getSize();
//TODO review//TODO review
if (size == BITS32) {
write8(0x29);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write8(0x29);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS8) {
write8(0x28);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
}
}
/**
* Create a SUB [dstReg+dstDisp], <srcReg>
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeSUB(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRM(0x29, srcReg.getNr(), dstReg, dstDisp, srcReg
.getNr());
}
/**
* Create a SUB dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeSUB(GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRR(0x29, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* Create a SUB dstReg, [srcReg+srcDisp]
*
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeSUB(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRM(0x2B, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
/**
* Create a TEST reg, imm32
*
* @param reg
* @param imm32
*/
public final void writeTEST(GPR reg, int imm32) {
testSize(reg, BITS8 | BITS16 | BITS32 | BITS64);
int size = reg.getSize();
if (reg == GPR.AL && isUByte(imm32)) {
writeTEST_AL(imm32);
} else if (reg == GPR.EAX && !isByte(imm32)) {
writeTEST_EAX(BITS32, imm32);
} else if ((size & (BITS32 | BITS64)) == size) {
write1bOpcodeModRR(0xF7, reg.getSize(), reg, 0);
write32(imm32);
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRR(0xF7, reg.getSize(), reg, 0);
write16(imm32);
} else if (size == BITS8) {
write1bOpcodeModRR(0xF6, reg.getSize(), reg, 0);
write8(imm32);
}
}
/**
* Create a TEST [reg+disp], imm32
*
* @param reg
* @param disp
* @param imm32
*/
public void writeTEST(int operandSize, GPR reg, int disp, int imm32) {
testSize(reg, BITS32 | BITS64);
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeModRM(0xF7, operandSize, reg, disp, 0);
write32(imm32);
}
/**
* Create a TEST [reg+disp], imm32
*
* @param reg
* @param disp
* @param imm32
*/
public void writeTEST(int operandSize, SR reg, int disp, int imm32) {
testOperandSize(operandSize, BITS32);
writeSegPrefix(reg);
write8(0xF7);
write8(0x05);
write32(disp);
write32(imm32);
}
/**
* Create a TEST reg1, reg2
*
* @param reg1
* @param reg2
*/
public void writeTEST(GPR reg1, GPR reg2) {
final int size = reg1.getSize();
if (size != reg2.getSize()) {
throw new IllegalArgumentException("Operand size mismatch");
}
testOperandSize(size, BITS8 | BITS16 | BITS32 | BITS64);
if (size == BITS32 || size == BITS64) {
write1bOpcodeModRR(0x85, reg1.getSize(), reg1, reg2.getNr());
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRR(0x85, reg1.getSize(), reg1, reg2.getNr());
} else if (size == BITS8) {
write1bOpcodeModRR(0x84, reg1.getSize(), reg1, reg2.getNr());
}
}
/**
* Create a TEST al, imm8
*
* @param value
*/
public final void writeTEST_AL(int value) {
write8(0xa8);
write8(value);
}
/**
* Create a TEST eax,imm32 or TEST rax,imm32
*
* @param value
*/
public final void writeTEST_EAX(int operandSize, int value) {
testOperandSize(operandSize, BITS32 | BITS64);
write1bOpcodeREXPrefix(operandSize, 0);
write8(0xa9);
write32(value);
}
public final void writeTEST(int operandSize, int destDisp, int imm32) {
testOperandSize(operandSize, BITS8 | BITS16 | BITS32);
//TODO review
if (operandSize == BITS32) {
write8(0xf7);
write8(5);
write32(destDisp);
write32(imm32);
} else if (operandSize == BITS16) {
write8(OSIZE_PREFIX);
write8(0xf7);
write8(5);
write32(destDisp);
write16(imm32);
} else if (operandSize == BITS8) {
write8(0xf6);
write8(5);
write32(destDisp);
write8(imm32);
}
}
/**
* Write my contents to the given stream.
*
* @param os
* @throws IOException
*/
public final void writeTo(OutputStream os) throws IOException {
os.write(m_data, 0, m_used);
}
/**
* @param dstDisp
* @param srcReg
*/
public void writeXCHG(int dstDisp, GPR srcReg) {
testSize(srcReg, BITS8 | BITS16 | BITS32);
int size = srcReg.getSize();
//TODO review
if (size == BITS32) {
write8(0x87);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write8(0x87);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
} else if (size == BITS8) {
write8(0x86);
write8(srcReg.getNr() << 3 | 5);
write32(dstDisp);
}
}
public void writeXCHG(SR dstReg, int dstDisp, GPR srcReg) {
testSize(srcReg, mode.getSize());
writeSegPrefix(dstReg);
write8(0x87);
write8(0x05 | srcReg.getNr() << 3);
write32(dstDisp);
}
public void writeXCHG(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
write1bOpcodeModRM(0x87, srcReg.getSize(), dstReg, dstDisp, srcReg
.getNr());
}
public void writeXCHG(GPR dstReg, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, mode.getSize());
if (dstReg == X86Register.EAX) {
write8(0x90 + srcReg.getNr());
} else if (srcReg == X86Register.EAX) {
write8(0x90 + dstReg.getNr());
} else {
write1bOpcodeModRR(0x87, dstReg.getSize(), dstReg, srcReg.getNr());
}
}
/**
* @param dstReg
* @param imm32
*/
public void writeXOR(GPR dstReg, int imm32) {
testSize(dstReg, BITS32 | BITS64);
if (dstReg == GPR.EAX) {
write8(0x35);
write32(imm32);
} else if (isByte(imm32)) {
write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 6);
write8(imm32);
} else {
write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 6);
write32(imm32);
}
}
/**
* @param dstReg
* @param dstDisp
* @param imm32
*/
public void writeXOR(int operandSize, GPR dstReg, int dstDisp, int imm32) {
testSize(dstReg, mode.getSize());
if (isByte(imm32)) {
write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 6);
write8(imm32);
} else {
write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 6);
write32(imm32);
}
}
/**
* Create a XOR [dstReg+dstDisp], srcReg
*
* @param dstReg
* @param dstDisp
* @param srcReg
*/
public final void writeXOR(GPR dstReg, int dstDisp, GPR srcReg) {
testSize(dstReg, mode.getSize());
testSize(srcReg, BITS8 | BITS16 | BITS32 | BITS64);
int size = srcReg.getSize();
if ((size & (BITS32 | BITS64)) == size) {
write1bOpcodeModRM(0x31, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS16) {
write8(OSIZE_PREFIX);
write1bOpcodeModRM(0x31, size, dstReg, dstDisp, srcReg.getNr());
} else if (size == BITS8) {
write1bOpcodeModRM(0x30, size, dstReg, dstDisp, srcReg.getNr());
}
}
/**
* Create a XOR dstReg, srcReg
*
* @param dstReg
* @param srcReg
*/
public final void writeXOR(GPR dstReg, GPR srcReg) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRR(0x31, dstReg.getSize(), dstReg, srcReg.getNr());
}
/**
* @param dstReg
* @param srcReg
* @param srcDisp
*/
public void writeXOR(GPR dstReg, GPR srcReg, int srcDisp) {
testSize(dstReg, BITS32 | BITS64);
testSize(srcReg, BITS32 | BITS64);
write1bOpcodeModRM(0x33, dstReg.getSize(), srcReg, srcDisp, dstReg
.getNr());
}
public void writeRDMSR() {
write8(0x0F);
write8(0x32);
}
public void writeWRMSR() {
write8(0x0F);
write8(0x30);
}
/**
* Does the given value fit in an 8-bit signed byte?
*
* @param value
* @return boolean
*/
public boolean isByte(int value) {
return byteValueEnabled && X86Utils.isByte(value);
}
/**
* Does the given value fit in an 8-bit signed byte?
*
* @param value
* @return boolean
*/
public boolean isUByte(int value) {
return byteValueEnabled && X86Utils.isUByte(value);
}
public boolean isByteValueEnabled() {
return byteValueEnabled;
}
public void setByteValueEnabled(boolean byteValueEnabled) {
this.byteValueEnabled = byteValueEnabled;
}
public boolean isRelJumpEnabled() {
return isRelJumpEnabled;
}
public void setRelJumpEnabled(boolean relJumpEnabled) {
isRelJumpEnabled = relJumpEnabled;
}
}