Disabled inObject check for write16
[jnode:svn-mirror.git] / core / src / core / org / jnode / assembler / x86 / X86BinaryAssembler.java
1 /*
2  * $Id$
3  *
4  * JNode.org
5  * Copyright (C) 2005 JNode.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published
9  * by the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License 
18  * along with this library; if not, write to the Free Software Foundation, 
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
20  */
21
22 package org.jnode.assembler.x86;
23  
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.LinkedList;
30 import java.util.Map;
31
32 import org.jnode.assembler.BootImageNativeStream;
33 import org.jnode.assembler.Label;
34 import org.jnode.assembler.NativeStream;
35 import org.jnode.assembler.ObjectResolver;
36 import org.jnode.assembler.UnresolvedObjectRefException;
37 import org.jnode.assembler.x86.X86Register.GPR;
38 import org.jnode.assembler.x86.X86Register.GPR32;
39 import org.jnode.assembler.x86.X86Register.GPR64;
40 import org.jnode.assembler.x86.X86Register.XMM;
41 import org.jnode.vm.classmgr.ObjectFlags;
42 import org.jnode.vm.classmgr.ObjectLayout;
43 import org.jnode.vm.classmgr.VmClassType;
44 import org.jnode.vm.classmgr.VmType;
45 import org.jnode.vm.x86.X86CpuID;
46
47 /**
48  * Implementation of AbstractX86Stream.
49  * 
50  * @author Ewout Prangsma (epr@users.sourceforge.net)
51  * @author Levente Santha
52  * @author Patrik Reali (patrik_reali@users.sourceforge.net)
53  */
54 public class X86BinaryAssembler extends X86Assembler implements X86Constants,
55                 BootImageNativeStream, X86Operation {
56         public static final class Key {
57
58                 private final Object key;
59
60                 public Key(Object key) {
61                         this.key = key;
62                 }
63
64                 /**
65                  * @param obj
66                  * @see java.lang.Object#equals(java.lang.Object)
67                  * @return True if obj is equal to this, false otherwise
68                  */
69                 public final boolean equals(Object obj) {
70                         /*
71                          * if (!(obj instanceof Key)) { return false;
72                          */
73                         obj = ((Key) obj).key;
74                         if (this.key instanceof Label) {
75                                 return key.equals(obj);
76                         } else {
77                                 return (obj == this.key);
78                         }
79                 }
80
81                 /**
82                  * @see java.lang.Object#hashCode()
83                  * @return The hashcode
84                  */
85                 public final int hashCode() {
86                         return key.hashCode();
87                 }
88
89         }
90
91         public class X86ObjectInfo extends NativeStream.ObjectInfo {
92
93                 private int m_objptr;
94
95                 X86ObjectInfo() {
96                         m_objptr = getLength();
97                 }
98
99                 /**
100                  * Mark the current location as the end of this object end fixup the
101                  * objectheader.
102                  */
103                 public void markEnd() {
104                         if (!inObject) {
105                                 throw new RuntimeException("inObject == false");
106                         }
107                         if (m_objptr == -1) {
108                                 throw new RuntimeException("markEnd has already been called");
109                         }
110                         align(ObjectLayout.OBJECT_ALIGN);
111                         final int size = getLength() - m_objptr;
112             if (isCode32()) {
113                 set32(m_objptr - (3 * 4), size);
114             } else {
115                 set64(m_objptr - (3 * 8), size);                
116             }
117                         m_objptr = -1;
118                         inObject = false;
119                 }
120         }
121
122         public final class UnresolvedOffset {
123                 private final int offset;
124
125                 private final int patchSize;
126
127                 public UnresolvedOffset(int offset, int patchSize) {
128                         if ((patchSize != 4) && (patchSize != 8)) {
129                                 throw new IllegalArgumentException("PatchSize: " + patchSize);
130                         }
131                         this.offset = offset;
132                         this.patchSize = patchSize;
133                 }
134
135                 public final int getOffset() {
136                         return offset;
137                 }
138
139                 public final int getPatchSize() {
140                         return patchSize;
141                 }
142         }
143
144         public class X86ObjectRef extends NativeStream.ObjectRef {
145
146                 private int dataOffset;
147
148                 private boolean isPublic;
149
150                 private boolean isRelJump;
151
152                 private LinkedList unresolvedLinks; // Array of data_offsets where
153
154                 public X86ObjectRef(Object object) {
155                         super(object);
156                         this.dataOffset = -1;
157                         this.unresolvedLinks = null;
158                         this.isPublic = false;
159                         this.isRelJump = false;
160                 }
161
162                 public void addUnresolvedLink(int offset, int patchSize) {
163                         if (unresolvedLinks == null) {
164                                 unresolvedLinks = new LinkedList();
165                         }
166                         unresolvedLinks.add(new UnresolvedOffset(offset, patchSize));
167                 }
168
169                 public int getOffset() throws UnresolvedObjectRefException {
170                         if (!isResolved()) {
171                                 throw new UnresolvedObjectRefException("Unresolved object: "
172                                                 + this);
173                         }
174                         return dataOffset;
175                 }
176
177                 public int[] getUnresolvedOffsets() {
178                         int cnt = unresolvedLinks.size();
179                         int[] offsets = new int[cnt];
180                         int ofs = 0;
181                         for (Iterator i = unresolvedLinks.iterator(); i.hasNext(); ofs++) {
182                                 offsets[ofs] = ((UnresolvedOffset) i.next()).getOffset();
183                         }
184                         return offsets;
185                 }
186
187                 public boolean isPublic() {
188                         return isPublic;
189                 }
190
191                 public boolean isRelJump() {
192                         return isRelJump;
193                 }
194
195                 public boolean isResolved() {
196                         return (dataOffset != -1);
197                 }
198
199                 /**
200                  * Link this objectref to the given objectref. That is, the offset of
201                  * this objectref will be set to the offset of the given objectref.
202                  * 
203                  * @param objectRef
204                  * @throws UnresolvedObjectRefException
205                  *             The given objectref is not resolved.
206                  */
207                 public void link(ObjectRef objectRef)
208                                 throws UnresolvedObjectRefException {
209                         if (!objectRef.isResolved()) {
210                                 throw new UnresolvedObjectRefException(objectRef.getObject()
211                                                 .toString());
212                         }
213                         setOffset(objectRef.getOffset());
214                 }
215
216                 public void setOffset(int offset) {
217                         if (this.dataOffset != -1) {
218                                 if ("".equals(getObject().toString())) {
219                                         return;
220                                 }
221                                 throw new RuntimeException(
222                                                 "Offset is already set. Duplicate labels? ("
223                                                                 + getObject() + ")");
224                         }
225                         if (offset < 0) {
226                                 throw new IllegalArgumentException("Offset: " + offset);
227                         }
228                         this.dataOffset = offset;
229                         if (unresolvedLinks != null) {
230                                 // Link all unresolved links
231                                 for (Iterator i = unresolvedLinks.iterator(); i.hasNext();) {
232                                         final UnresolvedOffset unrOfs = (UnresolvedOffset) i.next();
233                                         final int addr = unrOfs.getOffset();
234                                         if (unrOfs.getPatchSize() == 4) {
235                                                 resolve32(addr, offset);
236                                         } else {
237                                                 resolve64(addr, offset);
238                                         }
239                                 }
240                                 unresolvedLinks = null;
241                         }
242                 }
243
244                 /**
245                  * Resolve a 32-bit patch location.
246                  * 
247                  * @param addr
248                  * @param offset
249                  */
250                 private final void resolve32(int addr, int offset) {
251                         final int distance = offset - get32(addr);
252                         if (isRelJump() && (distance == 0)) {
253                                 if (get8(addr - 1) == 0xe9) // JMP
254                                 {
255                                         set8(addr - 1, 0x90); // NOP
256                                         set32(addr, 0x90909090); // 4 NOP's
257                                 } else if (get8(addr - 2) == 0x0f) // Jcc
258                                 {
259                                         set8(addr - 2, 0x90);
260                                         set8(addr - 1, 0x90);
261                                         set32(addr, 0x90909090); // 4 NOP's
262                                 } else {
263                                         set32(addr, distance);
264                                 }
265                         } else {
266                                 set32(addr, distance);
267                         }
268                 }
269
270                 /**
271                  * Resolve a 32-bit patch location.
272                  * 
273                  * @param addr
274                  * @param offset
275                  */
276                 private final void resolve64(int addr, int offset) {
277                         final long distance = offset - get64(addr);
278                         if (isRelJump()) {
279                                 throw new IllegalArgumentException(
280                                                 "RelJump not supported for 64-bit");
281                         } else {
282                                 set64(addr, distance);
283                         }
284                 }
285
286                 public void setPublic() {
287                         isPublic = true;
288                 }
289
290                 public void setRelJump() {
291                         isRelJump = true;
292                 }
293         }
294
295         private final int baseAddr;
296
297         private int dataLength;
298
299         private int growCount;
300
301         private final int growSize;
302
303         private final boolean haveCMOV;
304
305         private final int initialObjectRefsCapacity;
306
307         boolean inObject;
308
309         private byte[] m_data;
310
311         private int m_used;
312
313         private Map objectRefs; // Integer(labelnr),Integer(offset)
314
315         private ObjectResolver resolver;
316
317         /**
318          * Initialize this instance.
319          * 
320          * @param cpuId
321          * @param mode
322          * @param baseAddr
323          */
324         public X86BinaryAssembler(X86CpuID cpuId, Mode mode, int baseAddr) {
325                 this(cpuId, mode, baseAddr, 1024, 128, 1024);
326         }
327
328         /**
329          * Initialize this instance.
330          * 
331          * @param cpuId
332          * @param mode
333          * @param baseAddr
334          * @param initialObjectRefsCapacity
335          * @param initialSize
336          * @param growSize
337          */
338         public X86BinaryAssembler(X86CpuID cpuId, Mode mode, int baseAddr,
339                         int initialObjectRefsCapacity, int initialSize, int growSize) {
340                 super(cpuId, mode);
341                 this.m_data = new byte[initialSize];
342                 this.m_used = 0;
343                 this.baseAddr = baseAddr;
344                 this.inObject = false;
345                 this.initialObjectRefsCapacity = initialObjectRefsCapacity;
346                 this.growSize = growSize;
347                 this.haveCMOV = cpuId.hasFeature(X86CpuID.FEAT_CMOV);
348         }
349
350         /**
351          * Align on a given value
352          * 
353          * @param value
354          * @return The number of bytes needed to align.
355          */
356         public final int align(int value) {
357                 int count = 0;
358                 while ((getLength() % value) != 0) {
359                         write8(0x90); // Nop
360                         count++;
361                 }
362                 return count;
363         }
364
365         /**
366          * Remove all data and references.
367          */
368         public final void clear() {
369                 this.m_data = new byte[0];
370                 this.m_used = 0;
371                 this.objectRefs.clear();
372         }
373
374         private final void ensureSize(int extra) {
375                 if (m_used + extra >= dataLength) {
376                         int newLen;
377                         byte[] newArr;
378                         if (extra > growSize) {
379                                 newLen = dataLength + extra;
380                         } else {
381                                 newLen = dataLength + growSize;
382                         }
383                         newArr = new byte[newLen];
384                         System.arraycopy(m_data, 0, newArr, 0, m_used);
385                         m_data = newArr;
386                         dataLength = newLen;
387                         growCount++;
388                         // System.out.println("Growing stream buffer to " + newLen);
389                 }
390         }
391
392         public final int get32(int offset) {
393                 int v1 = m_data[offset++];
394                 int v2 = m_data[offset++];
395                 int v3 = m_data[offset++];
396                 int v4 = m_data[offset];
397                 return (v1 & 0xFF) | ((v2 & 0xFF) << 8) | ((v3 & 0xFF) << 16)
398                                 | ((v4 & 0xFF) << 24);
399         }
400
401         public final long get64(int offset) {
402                 long v1 = m_data[offset++];
403                 long v2 = m_data[offset++];
404                 long v3 = m_data[offset++];
405                 long v4 = m_data[offset++];
406                 long v5 = m_data[offset++];
407                 long v6 = m_data[offset++];
408                 long v7 = m_data[offset++];
409                 long v8 = m_data[offset];
410                 return (v1 & 0xFF) | ((v2 & 0xFF) << 8) | ((v3 & 0xFF) << 16)
411                                 | ((v4 & 0xFF) << 24) | ((v5 & 0xFF) << 32)
412                                 | ((v6 & 0xFF) << 40) | ((v7 & 0xFF) << 48)
413                                 | ((v8 & 0xFF) << 56);
414         }
415
416         public final int get8(int offset) {
417                 return (m_data[offset] & 0xFF);
418         }
419
420         /**
421          * Returns the base address.
422          * 
423          * @return long
424          */
425         public final long getBaseAddr() {
426                 return baseAddr;
427         }
428
429         /**
430          * Return the actual bytes. This array may be longer then getLength() *
431          * 
432          * @return The actual bytes
433          */
434         public final byte[] getBytes() {
435                 return m_data;
436         }
437
438         /**
439          * Get the length in bytes of valid data
440          * 
441          * @return the length of valid data
442          */
443         public final int getLength() {
444                 return m_used;
445         }
446
447         /**
448          * Gets an objectref for a given object.
449          * 
450          * @param keyObj
451          * @return ObjectRef
452          */
453         public final ObjectRef getObjectRef(Object keyObj) {
454                 if (keyObj == null) {
455                         throw new NullPointerException("Key cannot be null");
456                 }
457                 if (objectRefs == null) {
458                         objectRefs = new HashMap(initialObjectRefsCapacity);
459                 }
460                 Key key = new Key(keyObj);
461                 ObjectRef ref = (ObjectRef) objectRefs.get(key);
462                 if (ref != null) {
463                         return ref;
464                 }
465                 ref = new X86ObjectRef(keyObj);
466                 objectRefs.put(key, ref);
467                 return ref;
468         }
469
470         /**
471          * Gets all references of objects as instanceof ObjectRef
472          * 
473          * @return Collection
474          */
475         public final Collection getObjectRefs() {
476                 if (objectRefs == null) {
477                         objectRefs = new HashMap(initialObjectRefsCapacity);
478                 }
479                 return objectRefs.values();
480         }
481
482         public final int getObjectRefsCount() {
483                 if (objectRefs != null) {
484                         return objectRefs.size();
485                 } else {
486                         return 0;
487                 }
488         }
489
490         /**
491          * @return ObjectResolver
492          */
493         public final ObjectResolver getResolver() {
494                 return resolver;
495         }
496
497         /**
498          * Gets all unresolved references of objects as instanceof ObjectRef
499          * 
500          * @return Collection
501          */
502         public final Collection getUnresolvedObjectRefs() {
503                 final Collection coll = getObjectRefs();
504                 final LinkedList result = new LinkedList();
505                 for (Iterator i = coll.iterator(); i.hasNext();) {
506                         final ObjectRef ref = (ObjectRef) i.next();
507                         if (!ref.isResolved()) {
508                                 if (!(ref.getObject() instanceof Label)) {
509                                         result.add(ref);
510                                 }
511                         }
512                 }
513                 System.out.println("getUnresolvedObjectsRefs: count=" + result.size());
514                 return result;
515         }
516
517         /**
518          * Are there unresolved references?
519          * 
520          * @return True if there are unresolved references, false otherwise
521          */
522         public final boolean hasUnresolvedObjectRefs() {
523                 final Collection coll = getObjectRefs();
524                 for (Iterator i = coll.iterator(); i.hasNext();) {
525                         final ObjectRef ref = (ObjectRef) i.next();
526                         if (!ref.isResolved()) {
527                                 if (!(ref.getObject() instanceof Label)) {
528                                         return true;
529                                 }
530                         }
531                 }
532                 return false;
533         }
534
535         /**
536          * Is logging enabled. This method will only return true on on debug like
537          * implementations.
538          * 
539          * @return boolean
540          */
541         public boolean isLogEnabled() {
542                 return false;
543         }
544
545         /**
546          * @see org.jnode.assembler.x86.X86Assembler#isTextStream()
547          */
548         public boolean isTextStream() {
549                 return false;
550         }
551
552         /**
553          * Write a log message. This method is only implemented on debug like
554          * implementations.
555          * 
556          * @param msg
557          */
558         public void log(Object msg) {
559                 // Do nothing
560         }
561
562         public final void set32(int offset, int v32) {
563                 m_data[offset++] = (byte) (v32 & 0xFF);
564                 m_data[offset++] = (byte) ((v32 >> 8) & 0xFF);
565                 m_data[offset++] = (byte) ((v32 >> 16) & 0xFF);
566                 m_data[offset++] = (byte) ((v32 >> 24) & 0xFF);
567         }
568
569         public final void set64(int offset, long v64) {
570                 m_data[offset++] = (byte) (v64 & 0xFF);
571                 m_data[offset++] = (byte) ((v64 >> 8) & 0xFF);
572                 m_data[offset++] = (byte) ((v64 >> 16) & 0xFF);
573                 m_data[offset++] = (byte) ((v64 >> 24) & 0xFF);
574                 m_data[offset++] = (byte) ((v64 >> 32) & 0xFF);
575                 m_data[offset++] = (byte) ((v64 >> 40) & 0xFF);
576                 m_data[offset++] = (byte) ((v64 >> 48) & 0xFF);
577                 m_data[offset++] = (byte) ((v64 >> 56) & 0xFF);
578         }
579
580         public final void setWord(int offset, long word) {
581                 if (mode.is32()) {
582                         set32(offset, (int) word);
583                 } else {
584                         set64(offset, word);
585                 }
586         }
587
588         public final void set8(int offset, int v8) {
589                 m_data[offset] = (byte) v8;
590         }
591
592         public final ObjectRef setObjectRef(Object label) {
593                 X86ObjectRef ref = (X86ObjectRef) getObjectRef(label);
594                 ref.setOffset(m_used);
595                 return ref;
596         }
597
598         /**
599          * Sets the resolver.
600          * 
601          * @param resolver
602          *            The resolver to set
603          */
604         public void setResolver(ObjectResolver resolver) {
605                 this.resolver = resolver;
606         }
607
608         /**
609          * Start a new object and write its header. An ObjectInfo object is
610          * returned, on which the <code>markEnd</code> mehod must be called after
611          * all data has been written into the object.
612          * 
613          * @param cls
614          * @see ObjectInfo
615          * @return The info for the started object
616          */
617         public final ObjectInfo startObject(VmType cls) {
618                 if (inObject) {
619                         throw new RuntimeException(
620                                         "Cannot start an object within an object");
621                 }
622                 if (align(ObjectLayout.OBJECT_ALIGN) != 0) {
623                         throw new RuntimeException("Unaligned before startObject");
624                 }
625                 inObject = true;
626
627                 // The default header is 2 words long. The size fields add another
628                 // word, which adds up to 3 words which masy not be objectaligned.
629                 // Write some slack until it is aligned again
630                 int alignSlack = 0;
631                 final int threeWords = getWordSize() * 3;
632                 while (ObjectLayout.objectAlign(alignSlack + threeWords) != (alignSlack + threeWords)) {
633                         writeWord(0);
634                         alignSlack += getWordSize();
635                 }
636                 // System.out.println("alignSlack=" + alignSlack);
637
638                 writeWord(0); // Size
639                 writeWord(ObjectFlags.GC_DEFAULT_COLOR); // Flags
640                 if (cls == null) {
641                         throw new NullPointerException("cls==null");
642                 } else {
643                         final Object[] tib = ((VmClassType) cls).getTIB();
644                         if (tib[0] == null) {
645                                 throw new NullPointerException("tib[0]==null");
646                         }
647                         writeObjectRef(tib, 0, false);
648                 }
649                 return new X86ObjectInfo();
650         }
651
652         private void testDst(X86Register dst, int dstDisp) {
653                 if ((dst == X86Register.EBP) && (dstDisp == 0)) {
654                         throw new RuntimeException("Write to [EBP+0]");
655                 }
656         }
657
658         /**
659          * Dst register must have an 8-bits part. Valid for EAX, EBX, ECX, EDX,
660          * runtimeexception for others.
661          * 
662          * @param dst
663          */
664         private void testSuitableForBits8(X86Register dst) {
665                 if (!dst.isSuitableForBits8()) {
666                         throw new IllegalArgumentException("Register " + dst
667                                         + " is not suitable for BITS8 datasize");
668                 }
669         }
670
671         /**
672          * Remove count bytes from the end of the generated stream.
673          * 
674          * @param count
675          */
676         public void trim(int count) {
677                 if ((count < 0) || (count > m_used)) {
678                         throw new IllegalArgumentException("Invalid count value " + count);
679                 }
680                 m_used -= count;
681         }
682
683         public final void write(byte[] data, int ofs, int len) {
684                 /*
685                  * if (!inObject) { throw new IllegalArgumentException("Cannot write out
686                  * of an object");
687                  */
688                 ensureSize(len);
689                 System.arraycopy(data, ofs, m_data, m_used, len);
690                 m_used += len;
691         }
692
693         public final void write16(int v16) {
694
695                 //if (!inObject) {
696                 //      throw new IllegalArgumentException("Cannot write out of an object");
697                 //}
698                 ensureSize(2);
699                 m_data[m_used++] = (byte) (v16 & 0xFF);
700                 m_data[m_used++] = (byte) ((v16 >> 8) & 0xFF);
701         }
702
703         public final void write32(int v32) {
704                 /*
705                  * if (!inObject) { throw new IllegalArgumentException("Cannot write out
706                  * of an object");
707                  */
708                 ensureSize(4);
709                 m_data[m_used++] = (byte) (v32 & 0xFF);
710                 m_data[m_used++] = (byte) ((v32 >> 8) & 0xFF);
711                 m_data[m_used++] = (byte) ((v32 >> 16) & 0xFF);
712                 m_data[m_used++] = (byte) ((v32 >> 24) & 0xFF);
713         }
714
715         public final void write64(long v64) {
716                 write32((int) (v64 & 0xFFFFFFFF)); // lsb
717                 write32((int) ((v64 >>> 32) & 0xFFFFFFFF)); // msb
718         }
719
720         /**
721          * Write an 8-bit unsigned byte.
722          * 
723          * @param v8
724          */
725         public final void write8(int v8) {
726                 ensureSize(1);
727                 m_data[m_used++] = (byte) (v8 & 0xFF);
728         }
729
730         /**
731          * Create a ADC dstReg, imm32
732          * 
733          * @param dstReg
734          * @param imm32
735          */
736         public void writeADC(GPR dstReg, int imm32) {
737                 if (X86Utils.isByte(imm32)) {
738                         write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 2);
739                         write8(imm32);
740                 } else {
741                         write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 2);
742                         write32(imm32);
743                 }
744         }
745
746         /**
747          * @see org.jnode.assembler.x86.X86Assembler#writeADC(int, GPR, int, int)
748          */
749         public void writeADC(int operandSize, GPR dstReg, int dstDisp, int imm32) {
750                 if (X86Utils.isByte(imm32)) {
751                         write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 2);
752                         write8(imm32);
753                 } else {
754                         write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 2);
755                         write32(imm32);
756                 }
757         }
758
759         /**
760          * Create a ADC [dstReg+dstDisp], <srcReg>
761          * 
762          * @param dstReg
763          * @param dstDisp
764          * @param srcReg
765          */
766         public final void writeADC(GPR dstReg, int dstDisp, GPR srcReg) {
767                 write1bOpcodeModRM(0x11, srcReg.getSize(), dstReg, dstDisp, srcReg
768                                 .getNr());
769         }
770
771         /**
772          * Create a ADC dstReg, srcReg
773          * 
774          * @param dstReg
775          * @param srcReg
776          */
777         public void writeADC(GPR dstReg, GPR srcReg) {
778                 write1bOpcodeModRR(0x11, dstReg.getSize(), dstReg, srcReg.getNr());
779         }
780
781         /**
782          * Create a ADC dstReg, [srcReg+srcDisp]
783          * 
784          * @param dstReg
785          * @param srcReg
786          * @param srcDisp
787          */
788         public void writeADC(GPR dstReg, GPR srcReg, int srcDisp) {
789                 write1bOpcodeModRM(0x13, dstReg.getSize(), srcReg, srcDisp, dstReg
790                                 .getNr());
791         }
792
793         /**
794          * Create an ADD dstReg, imm32
795          * 
796          * @param dstReg
797          * @param imm32
798          */
799         public void writeADD(GPR dstReg, int imm32) {
800                 if (X86Utils.isByte(imm32)) {
801                         write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 0);
802                         write8(imm32);
803                 } else {
804                         write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 0);
805                         write32(imm32);
806                 }
807         }
808
809         /**
810          * Create a ADD [dstReg+dstDisp], imm32
811          * 
812          * @param dstReg
813          * @param dstDisp
814          * @param imm32
815          */
816         public void writeADD(int operandSize, GPR dstReg, int dstDisp, int imm32) {
817                 if (X86Utils.isByte(imm32)) {
818                         write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 0);
819                         write8(imm32);
820                 } else {
821                         write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 0);
822                         write32(imm32);
823                 }
824         }
825
826         /**
827          * Create a ADD [dstReg+dstDisp], srcReg
828          * 
829          * @param dstReg
830          * @param dstDisp
831          * @param srcReg
832          */
833         public final void writeADD(GPR dstReg, int dstDisp, GPR srcReg) {
834                 write1bOpcodeModRM(0x01, srcReg.getSize(), dstReg, dstDisp, srcReg
835                                 .getNr());
836         }
837
838         /**
839          * Create a ADD dstReg, srcReg
840          * 
841          * @param dstReg
842          * @param srcReg
843          */
844         public final void writeADD(GPR dstReg, GPR srcReg) {
845                 write1bOpcodeModRR(0x01, dstReg.getSize(), dstReg, srcReg.getNr());
846         }
847
848         /**
849          * Create a ADD dstReg, [srcReg+srcDisp]
850          * 
851          * @param dstReg
852          * @param srcReg
853          * @param srcDisp
854          */
855         public final void writeADD(GPR dstReg, GPR srcReg, int srcDisp) {
856                 write1bOpcodeModRM(0x03, dstReg.getSize(), srcReg, srcDisp, dstReg
857                                 .getNr());
858         }
859
860         /**
861          * Create a AND dstReg, imm32
862          * 
863          * @param dstReg
864          * @param imm32
865          */
866         public final void writeAND(GPR dstReg, int imm32) {
867                 if (X86Utils.isByte(imm32)) {
868                         write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 4);
869                         write8(imm32);
870                 } else {
871                         write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 4);
872                         write32(imm32);
873                 }
874         }
875
876         /**
877          * 
878          * @param dstReg
879          * @param dstDisp
880          * @param imm32
881          */
882         public void writeAND(int operandSize, GPR dstReg, int dstDisp, int imm32) {
883                 if (X86Utils.isByte(imm32)) {
884                         write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 4);
885                         write8(imm32);
886                 } else {
887                         write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 4);
888                         write32(imm32);
889                 }
890         }
891
892         /**
893          * Create a AND [dstReg+dstDisp], srcReg
894          * 
895          * @param dstReg
896          * @param dstDisp
897          * @param srcReg
898          */
899         public final void writeAND(GPR dstReg, int dstDisp, GPR srcReg) {
900                 write1bOpcodeModRM(0x21, srcReg.getSize(), dstReg, dstDisp, srcReg
901                                 .getNr());
902         }
903
904         /**
905          * Create a AND dstReg, srcReg
906          * 
907          * @param dstReg
908          * @param srcReg
909          */
910         public final void writeAND(GPR dstReg, GPR srcReg) {
911                 write1bOpcodeModRR(0x21, dstReg.getSize(), dstReg, srcReg.getNr());
912         }
913
914         /**
915          * 
916          * @param dstReg
917          * @param srcReg
918          * @param srcDisp
919          */
920         public void writeAND(GPR dstReg, GPR srcReg, int srcDisp) {
921                 write1bOpcodeModRM(0x23, dstReg.getSize(), srcReg, srcDisp, dstReg
922                                 .getNr());
923         }
924
925         public void writeArithSSEDOp(int operation, XMM dst, GPR src, int srcDisp) {
926                 final int opcode3 = sseOperationToOpcode3(operation);
927                 write3bOpcodeModRM(0xF2, 0x0F, opcode3, 0, src, srcDisp, dst.getNr());
928         }
929
930         public void writeArithSSEDOp(int operation, XMM dst, XMM src) {
931                 final int opcode3 = sseOperationToOpcode3(operation);
932                 write3bOpcodeModRR(0xF2, 0x0F, opcode3, 0, src, dst.getNr());
933         }
934
935         public void writeArithSSESOp(int operation, XMM dst, GPR src, int srcDisp) {
936                 final int opcode3 = sseOperationToOpcode3(operation);
937                 write3bOpcodeModRM(0xF3, 0x0F, opcode3, 0, src, srcDisp, dst.getNr());
938         }
939
940         public void writeArithSSESOp(int operation, XMM dst, XMM src) {
941                 final int opcode3 = sseOperationToOpcode3(operation);
942                 write3bOpcodeModRR(0xF3, 0x0F, opcode3, 0, src, dst.getNr());
943         }
944
945         /**
946          * Convert an SSE operation into the 3'rd opcode byte for that operation.
947          * 
948          * @param operation
949          * @return the 3'rd opcode byte.
950          */
951         private final int sseOperationToOpcode3(int operation) {
952                 final int opcode3;
953                 switch (operation) {
954                 case SSE_ADD:
955                         opcode3 = 0x58;
956                         break;
957                 case SSE_SUB:
958                         opcode3 = 0x5C;
959                         break;
960                 case SSE_MUL:
961                         opcode3 = 0x59;
962                         break;
963                 case SSE_DIV:
964                         opcode3 = 0x5E;
965                         break;
966                 default:
967                         throw new IllegalArgumentException("Invalid SSE operation "
968                                         + operation);
969                 }
970                 return opcode3;
971         }
972
973         /**
974          * Create a bound lReg, [rReg+rDisp]
975          * 
976          * @param lReg
977          * @param rReg
978          * @param rDisp
979          */
980         public final void writeBOUND(GPR lReg, GPR rReg, int rDisp) {
981                 if (code64) {
982                         throw new InvalidOpcodeException();
983                 }
984                 write1bOpcodeModRM(0x62, 0, rReg, rDisp, lReg.getNr());
985         }
986
987         /**
988          * @see org.jnode.assembler.x86.X86Assembler#writeBreakPoint()
989          */
990         public void writeBreakPoint() {
991                 write8(0xCC);
992         }
993
994         /**
995          * Create a relative call to a given label
996          * 
997          * @param label
998          */
999         public final void writeCALL(Label label) {
1000                 write8(0xe8); // call rel32
1001                 writeRelativeObjectRef(label);
1002         }
1003
1004         /**
1005          * Create a call to address stored at the given offset in the given table
1006          * pointer.
1007          * 
1008          * @param tablePtr
1009          * @param offset
1010          * @param rawAddress
1011          *            If true, tablePtr is a raw address
1012          */
1013         public final void writeCALL(Object tablePtr, int offset, boolean rawAddress) {
1014         if (code64) {
1015             throw new InvalidOpcodeException();
1016         }
1017                 write8(0xFF); // Opcode
1018                 write8(0x15); // effective address == disp32
1019                 writeObjectRef(tablePtr, offset, rawAddress);
1020         }
1021
1022         /**
1023          * @see org.jnode.assembler.x86.X86Assembler#writeCALL(GPR)
1024          */
1025         public void writeCALL(GPR reg) {
1026                 testSize(reg, mode.getSize());
1027                 // Since CALL in 64-bit mode always use 64-bit targets, we
1028                 // specify a 0 operand size, so we won't get a REX prefix
1029                 write1bOpcodeModRR(0xFF, 0, reg, 2);
1030         }
1031
1032         /**
1033          * Create a call to address stored at the given [reg+offset].
1034          * 
1035          * @param reg
1036          * @param offset
1037          */
1038         public final void writeCALL(GPR reg, int offset) {
1039                 // Since CALL in 64-bit mode always use 64-bit targets, we
1040                 // specify a 0 operand size, so we won't get a REX prefix
1041                 write1bOpcodeModRM(0xFF, 0, reg, offset, 2);
1042         }
1043
1044         /**
1045          * @see org.jnode.assembler.x86.X86Assembler#writeCALL(GPR, GPR, int, int)
1046          */
1047         public void writeCALL(GPR regBase, GPR regIndex, int scale, int disp) {
1048                 // Since CALL in 64-bit mode always use 64-bit targets, we
1049                 // specify a 0 operand size, so we won't get a REX prefix
1050                 write1bOpcodeModRMSib(0xFF, 0, regBase, disp, 2, scale, regIndex);
1051         }
1052
1053         /**
1054          * Create a cdq
1055      * Sign extend EAX to EDX:EAX in 32-bit operand size.
1056      * Sign extend RAX to RDX:RAX in 64-bit operand size.
1057          */
1058         public final void writeCDQ(int operandSize) {
1059         testOperandSize(operandSize, BITS32 | BITS64);
1060         if (operandSize == BITS64) {
1061             if (!code64) {
1062                 throw new InvalidOpcodeException();
1063             }
1064             write8(REX_W_PREFIX);
1065         }
1066                 write8(0x99);
1067         }
1068
1069         /**
1070          * Create a cdqe. Sign extend EAX to RAX. Only valid in 64-bit mode.
1071          */
1072         public void writeCDQE() throws InvalidOpcodeException {
1073                 if (!code64) {
1074                         throw new InvalidOpcodeException();
1075                 }
1076         write8(REX_W_PREFIX);
1077                 write8(0x98);
1078         }
1079
1080         /**
1081          * Create a CMOVcc dst,src
1082          * 
1083          * @param ccOpcode
1084          * @param dst
1085          * @param src
1086          */
1087         public void writeCMOVcc(int ccOpcode, GPR dst, GPR src) {
1088                 if (!haveCMOV) {
1089                         throw new InvalidOpcodeException("CMOVcc not supported");
1090                 }
1091                 write2bOpcodeModRR(0x0F, ccOpcode - 0x40, src.getSize(), src, dst
1092                                 .getNr());
1093         }
1094
1095         /**
1096          * Create a CMOVcc dst,[src+srcDisp]
1097          * 
1098          * @param dst
1099          * @param src
1100          * @param srcDisp
1101          */
1102         public void writeCMOVcc(int ccOpcode, GPR dst, GPR src, int srcDisp) {
1103                 if (!haveCMOV) {
1104                         throw new InvalidOpcodeException("CMOVcc not supported");
1105                 }
1106                 write2bOpcodeModRM(0x0F, ccOpcode - 0x40, dst.getSize(), src, srcDisp,
1107                                 dst.getNr());
1108         }
1109
1110         /**
1111          * Create a CMP [reg1+disp], reg2
1112          * 
1113          * @param reg1
1114          * @param disp
1115          * @param reg2
1116          */
1117         public void writeCMP(GPR reg1, int disp, GPR reg2) {
1118                 write1bOpcodeModRM(0x39, reg2.getSize(), reg1, disp, reg2.getNr());
1119         }
1120
1121         /**
1122          * Create a CMP reg1, reg2
1123          * 
1124          * @param reg1
1125          * @param reg2
1126          */
1127         public final void writeCMP(GPR reg1, GPR reg2) {
1128                 write1bOpcodeModRR(0x39, reg1.getSize(), reg1, reg2.getNr());
1129         }
1130
1131         /**
1132          * Create a CMP reg1, [reg2+disp]
1133          * 
1134          * @param reg1
1135          * @param reg2
1136          * @param disp
1137          */
1138         public void writeCMP(GPR reg1, GPR reg2, int disp) {
1139                 write1bOpcodeModRM(0x3b, reg1.getSize(), reg2, disp, reg1.getNr());
1140         }
1141
1142         /**
1143          * Create a CMP reg, imm32
1144          * 
1145          * @param reg
1146          * @param imm32
1147          */
1148         public final void writeCMP_Const(GPR reg, int imm32) {
1149                 if (X86Utils.isByte(imm32)) {
1150                         write1bOpcodeModRR(0x83, reg.getSize(), reg, 7);
1151                         write8(imm32);
1152                 } else {
1153                         write1bOpcodeModRR(0x81, reg.getSize(), reg, 7);
1154                         write32(imm32);
1155                 }
1156         }
1157
1158         /**
1159          * Create a CMP [reg+disp], imm32
1160          * 
1161          * @param reg
1162          * @param disp
1163          * @param imm32
1164          */
1165         public void writeCMP_Const(int operandSize, GPR reg, int disp, int imm32) {
1166                 if (X86Utils.isByte(imm32)) {
1167                         write1bOpcodeModRM(0x83, operandSize, reg, disp, 7);
1168                         write8(imm32);
1169                 } else {
1170                         write1bOpcodeModRM(0x81, operandSize, reg, disp, 7);
1171                         write32(imm32);
1172                 }
1173         }
1174
1175         /**
1176          * Create a CMP eax,imm32 or CMP rax,imm32
1177          * 
1178          * @param imm32
1179          */
1180         public final void writeCMP_EAX(int operandSize, int imm32) {
1181                 testOperandSize(operandSize, BITS32 | BITS64);        
1182                 write1bOpcodeREXPrefix(operandSize, 0);
1183                 write8(0x3d);
1184                 write32(imm32);
1185         }
1186
1187         /**
1188          * Create a CMP [reg+regDisp], imm32
1189          * 
1190          * @param memPtr
1191          * @param imm32
1192          */
1193         public final void writeCMP_MEM(int operandSize, int memPtr, int imm32) {
1194                 testOperandSize(operandSize, BITS32 | BITS64);
1195                 write1bOpcodeREXPrefix(operandSize, 0);
1196                 write8(0x81); // Opcode
1197                 write8(0x3D); // effective address == disp32
1198                 write32(memPtr);
1199                 write32(imm32);
1200         }
1201
1202         /**
1203          * Create a CMP reg,[memPtr]
1204          * 
1205          * @param reg
1206          * @param memPtr
1207          */
1208         public void writeCMP_MEM(GPR reg, int memPtr) {
1209                 if (code64) {
1210                         throw new InvalidOpcodeException("Not implemented");
1211                 }
1212                 write8(0x3b); // opcode
1213                 write8((reg.getNr() << 3) | 5); // disp32
1214                 write32(memPtr);
1215         }
1216
1217         /**
1218          * Create a CMPXCHG dword [dstReg], srcReg
1219          * 
1220          * @param dstReg
1221          * @param dstDisp
1222          * @param srcReg
1223          * @param lock
1224          */
1225         public final void writeCMPXCHG_EAX(GPR dstReg, int dstDisp, GPR srcReg,
1226                         boolean lock) {
1227                 if (lock) {
1228                         write8(0xF0);
1229                 }
1230                 write2bOpcodeModRM(0x0F, 0xB1, srcReg.getSize(), dstReg, dstDisp,
1231                                 srcReg.getNr());
1232         }
1233
1234         /**
1235          * Create a dec reg32
1236          * 
1237          * @param dstReg
1238          */
1239         public final void writeDEC(GPR dstReg) {
1240                 if (code32) {
1241                         write8(0x48 + dstReg.getNr());
1242                 } else {
1243                         write1bOpcodeModRR(0xFF, dstReg.getSize(), dstReg, 1);
1244                 }
1245         }
1246
1247         /**
1248          * Create a dec dword [dstReg+dstDisp]
1249          * 
1250          * @param dstReg
1251          * @param dstDisp
1252          */
1253         public final void writeDEC(int operandSize, GPR dstReg, int dstDisp) {
1254                 testOperandSize(operandSize, BITS32 | BITS64);
1255                 write1bOpcodeModRM(0xff, operandSize, dstReg, dstDisp, 1);
1256         }
1257
1258         /**
1259          * Create a fadd dword [srcReg+srcDisp]
1260          * 
1261          * @param srcReg
1262          * @param srcDisp
1263          */
1264         public final void writeFADD32(GPR srcReg, int srcDisp) {
1265                 write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 0);
1266         }
1267
1268         /**
1269          * Create a fadd qword [srcReg+srcDisp]
1270          * 
1271          * @param srcReg
1272          * @param srcDisp
1273          */
1274         public final void writeFADD64(GPR srcReg, int srcDisp) {
1275                 write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 0);
1276         }
1277
1278         /**
1279          * @see org.jnode.assembler.x86.X86Assembler#writeFADDP(X86Register)
1280          */
1281         public void writeFADDP(X86Register fpuReg) {
1282                 write8(0xde);
1283                 write8(0xc0 + fpuReg.getNr());
1284         }
1285
1286         /**
1287          * Create a fchs
1288          */
1289         public final void writeFCHS() {
1290                 write8(0xd9);
1291                 write8(0xe0);
1292         }
1293
1294         /**
1295          * Create a fdiv dword [srcReg+srcDisp]
1296          * 
1297          * @param srcReg
1298          * @param srcDisp
1299          */
1300         public final void writeFDIV32(GPR srcReg, int srcDisp) {
1301                 write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 6);
1302         }
1303
1304         /**
1305          * Create a fdiv qword [srcReg+srcDisp]
1306          * 
1307          * @param srcReg
1308          * @param srcDisp
1309          */
1310         public final void writeFDIV64(GPR srcReg, int srcDisp) {
1311                 write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 6);
1312         }
1313
1314         /**
1315          * @see org.jnode.assembler.x86.X86Assembler#writeFDIVP(X86Register)
1316          */
1317         public void writeFDIVP(X86Register fpuReg) {
1318                 write8(0xde);
1319                 write8(0xf8 + fpuReg.getNr());
1320         }
1321
1322         /**
1323          * Create a ffree
1324          * 
1325          * @param fReg
1326          */
1327         public final void writeFFREE(X86Register fReg) {
1328                 write8(0xdd);
1329                 write8(0xc0 | fReg.getNr());
1330         }
1331
1332         /**
1333          * Create a fild dword [dstReg+dstDisp]
1334          * 
1335          * @param dstReg
1336          * @param dstDisp
1337          */
1338         public final void writeFILD32(GPR dstReg, int dstDisp) {
1339                 write1bOpcodeModRM(0xdb, 0, dstReg, dstDisp, 0);
1340         }
1341
1342         /**
1343          * Create a fild qword [dstReg+dstDisp]
1344          * 
1345          * @param dstReg
1346          * @param dstDisp
1347          */
1348         public final void writeFILD64(GPR dstReg, int dstDisp) {
1349                 write1bOpcodeModRM(0xdf, 0, dstReg, dstDisp, 5);
1350         }
1351
1352         /**
1353          * Create a fistp dword [dstReg+dstDisp]
1354          * 
1355          * @param dstReg
1356          * @param dstDisp
1357          */
1358         public final void writeFISTP32(GPR dstReg, int dstDisp) {
1359                 write1bOpcodeModRM(0xdb, 0, dstReg, dstDisp, 3);
1360         }
1361
1362         /**
1363          * Create a fistp qword [dstReg+dstDisp]
1364          * 
1365          * @param dstReg
1366          * @param dstDisp
1367          */
1368         public final void writeFISTP64(GPR dstReg, int dstDisp) {
1369                 write1bOpcodeModRM(0xdf, 0, dstReg, dstDisp, 7);
1370         }
1371
1372         /**
1373          * Create a fld dword [srcReg+srcDisp]
1374          * 
1375          * @param srcReg
1376          * @param srcDisp
1377          */
1378         public final void writeFLD32(GPR srcReg, int srcDisp) {
1379                 write1bOpcodeModRM(0xd9, 0, srcReg, srcDisp, 0);
1380         }
1381
1382         /**
1383          * Create a fld dword [srcBaseReg+scrIndexReg*srcScale+srcDisp]
1384          * 
1385          * @param srcBaseReg
1386          * @param srcIndexReg
1387          * @param srcScale
1388          * @param srcDisp
1389          */
1390         public void writeFLD32(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
1391                         int srcDisp) {
1392                 write1bOpcodeModRMSib(0xd9, 0, srcBaseReg, srcDisp, 0, srcScale,
1393                                 srcIndexReg);
1394         }
1395
1396         /**
1397          * Create a fld qword [srcReg+srcDisp]
1398          * 
1399          * @param srcReg
1400          * @param srcDisp
1401          */
1402         public final void writeFLD64(GPR srcReg, int srcDisp) {
1403                 write1bOpcodeModRM(0xdd, 0, srcReg, srcDisp, 0);
1404         }
1405
1406         /**
1407          * Create a fld qword [srcBaseReg+scrIndexReg*srcScale+srcDisp]
1408          * 
1409          * @param srcBaseReg
1410          * @param srcIndexReg
1411          * @param srcScale
1412          * @param srcDisp
1413          */
1414         public void writeFLD64(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
1415                         int srcDisp) {
1416                 write1bOpcodeModRMSib(0xdd, 0, srcBaseReg, srcDisp, 0, srcScale,
1417                                 srcIndexReg);
1418         }
1419
1420         /**
1421          * Create a fmul dword [srcReg+srcDisp]
1422          * 
1423          * @param srcReg
1424          * @param srcDisp
1425          */
1426         public final void writeFMUL32(GPR srcReg, int srcDisp) {
1427                 write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 1);
1428         }
1429
1430         /**
1431          * Create a fmul qword [srcReg+srcDisp]
1432          * 
1433          * @param srcReg
1434          * @param srcDisp
1435          */
1436         public final void writeFMUL64(GPR srcReg, int srcDisp) {
1437                 write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 1);
1438         }
1439
1440         /**
1441          * @see org.jnode.assembler.x86.X86Assembler#writeFMULP(X86Register)
1442          */
1443         public void writeFMULP(X86Register fpuReg) {
1444                 write8(0xde);
1445                 write8(0xc8 + fpuReg.getNr());
1446         }
1447
1448         /**
1449          * Create a fnstsw, Store fp status word in AX
1450          */
1451         public final void writeFNSTSW_AX() {
1452                 write8(0xdf);
1453                 write8(0xe0);
1454         }
1455
1456         /**
1457          * Create a fprem
1458          */
1459         public final void writeFPREM() {
1460                 write8(0xd9);
1461                 write8(0xf8);
1462         }
1463
1464         /**
1465          * @see org.jnode.assembler.x86.X86Assembler#writeFSTP(X86Register)
1466          */
1467         public void writeFSTP(X86Register fpuReg) {
1468                 write8(0xDD);
1469                 write8(0xD8 + fpuReg.getNr());
1470         }
1471
1472         /**
1473          * Create a fstp dword [dstReg+dstDisp]
1474          * 
1475          * @param dstReg
1476          * @param dstDisp
1477          */
1478         public final void writeFSTP32(GPR dstReg, int dstDisp) {
1479                 write1bOpcodeModRM(0xd9, 0, dstReg, dstDisp, 3);
1480         }
1481
1482         /**
1483          * Create a fstp qword [dstReg+dstDisp]
1484          * 
1485          * @param dstReg
1486          * @param dstDisp
1487          */
1488         public final void writeFSTP64(GPR dstReg, int dstDisp) {
1489                 write1bOpcodeModRM(0xdd, 0, dstReg, dstDisp, 3);
1490         }
1491
1492         /**
1493          * Create a fsub dword [srcReg+srcDisp]
1494          * 
1495          * @param srcReg
1496          * @param srcDisp
1497          */
1498         public final void writeFSUB32(GPR srcReg, int srcDisp) {
1499                 write1bOpcodeModRM(0xd8, 0, srcReg, srcDisp, 4);
1500         }
1501
1502         /**
1503          * Create a fsub qword [srcReg+srcDisp]
1504          * 
1505          * @param srcReg
1506          * @param srcDisp
1507          */
1508         public final void writeFSUB64(GPR srcReg, int srcDisp) {
1509                 write1bOpcodeModRM(0xdc, 0, srcReg, srcDisp, 4);
1510         }
1511
1512         /**
1513          * @see org.jnode.assembler.x86.X86Assembler#writeFSUBP(X86Register)
1514          */
1515         public void writeFSUBP(X86Register fpuReg) {
1516                 write8(0xde);
1517                 write8(0xe8 + fpuReg.getNr());
1518         }
1519
1520         /**
1521          * Create a fucompp, Compare - Pop twice
1522          */
1523         public final void writeFUCOMPP() {
1524                 write8(0xda);
1525                 write8(0xe9);
1526         }
1527
1528         /**
1529          * @see org.jnode.assembler.x86.X86Assembler#writeFXCH(X86Register)
1530          */
1531         public void writeFXCH(X86Register fpuReg) {
1532                 write8(0xd9);
1533                 write8(0xc8 + fpuReg.getNr());
1534         }
1535
1536         /**
1537          * Create an idiv edx:eax, srcReg.
1538          * 
1539          * If srcReg is 64-bit, the idiv rdx:rax, srcReg is created.
1540          * 
1541          * @param srcReg
1542          */
1543         public final void writeIDIV_EAX(GPR srcReg) {
1544                 write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 7);
1545         }
1546
1547         /**
1548          * @param srcReg
1549          * @param srcDisp
1550          */
1551         public void writeIDIV_EAX(int operandSize, GPR srcReg, int srcDisp) {
1552                 testOperandSize(operandSize, BITS32 | BITS64);
1553                 write1bOpcodeModRM(0xF7, operandSize, srcReg, srcDisp, 7);
1554         }
1555
1556         /**
1557          * 
1558          * @param dstReg
1559          * @param srcReg
1560          */
1561         public void writeIMUL(GPR dstReg, GPR srcReg) {
1562                 write2bOpcodeModRR(0x0F, 0xAF, srcReg.getSize(), srcReg, dstReg.getNr());
1563         }
1564
1565         /**
1566          * 
1567          * @param dstReg
1568          * @param srcReg
1569          * @param srcDisp
1570          */
1571         public void writeIMUL(GPR dstReg, GPR srcReg, int srcDisp) {
1572                 write2bOpcodeModRM(0x0F, 0xAF, dstReg.getSize(), srcReg, srcDisp,
1573                                 dstReg.getNr());
1574         }
1575
1576         /**
1577          * 
1578          * @param dstReg
1579          * @param srcReg
1580          * @param imm32
1581          */
1582         public void writeIMUL_3(GPR dstReg, GPR srcReg, int imm32) {
1583                 write1bOpcodeModRR(0x69, dstReg.getSize(), srcReg, dstReg.getNr());
1584                 write32(imm32);
1585         }
1586
1587         /**
1588          * 
1589          * @param dstReg
1590          * @param srcReg
1591          * @param srcDisp
1592          * @param imm32
1593          */
1594         public void writeIMUL_3(GPR dstReg, GPR srcReg, int srcDisp, int imm32) {
1595                 write1bOpcodeModRM(0x69, dstReg.getSize(), srcReg, srcDisp, dstReg
1596                                 .getNr());
1597                 write32(imm32);
1598         }
1599
1600         /**
1601          * Create a imul eax, srcReg.
1602          * 
1603          * If srcReg is 64-bit, an imul rax, srcReg is created.
1604          * 
1605          * @param srcReg
1606          */
1607         public final void writeIMUL_EAX(GPR srcReg) {
1608                 write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 5);
1609         }
1610
1611         /**
1612          * Create a inc reg32
1613          * 
1614          * @param dstReg
1615          */
1616         public final void writeINC(GPR dstReg) {
1617                 if (code32) {
1618                         write8(0x40 + dstReg.getNr());
1619                 } else {
1620                         write1bOpcodeModRR(0xFF, dstReg.getSize(), dstReg, 0);
1621                 }
1622         }
1623
1624         /**
1625          * Create a inc size [dstReg+disp]
1626          * 
1627          * @param dstReg
1628          */
1629         public final void writeINC(int operandSize, GPR dstReg, int disp) {
1630                 testOperandSize(operandSize, BITS32 | BITS64);
1631                 write1bOpcodeModRM(0xFF, operandSize, dstReg, disp, 0);
1632         }
1633
1634         /**
1635          * Create a int vector
1636          * 
1637          * @param vector
1638          */
1639         public final void writeINT(int vector) {
1640                 write8(0xCD);
1641                 write8(vector);
1642         }
1643
1644         /**
1645          * Create a conditional jump to a label The opcode sequence is: 0x0f
1646          * <jumpOpcode><rel32>
1647          * 
1648          * @param label
1649          * @param jumpOpcode
1650          */
1651         public final void writeJCC(Label label, int jumpOpcode) {
1652                 write8(0x0f); // jxx rel32
1653                 write8(jumpOpcode);
1654                 writeRelativeObjectRef(label);
1655         }
1656
1657         /**
1658          * Create a relative jump to a given label
1659          * 
1660          * @param label
1661          */
1662         public final void writeJMP(Label label) {
1663                 write8(0xe9); // jmp rel32
1664                 writeRelativeObjectRef(label);
1665         }
1666
1667         /**
1668          * Create a absolute jump to address stored at the given offset in the given
1669          * table pointer.
1670          * 
1671          * @param tablePtr
1672          * @param offset
1673          * @param rawAddress
1674          *            If true, tablePtr is a raw address
1675          */
1676         public void writeJMP(Object tablePtr, int offset, boolean rawAddress) {
1677         if (code64) {
1678             throw new InvalidOpcodeException();
1679         }
1680                 write8(0xFF); // Opcode
1681                 write8(0x25); // effective address == disp32
1682                 writeObjectRef(tablePtr, offset, rawAddress);
1683         }
1684
1685         /**
1686          * Create a absolute jump to address stored at the given offset (in
1687          * register) in the given table pointer.
1688          * 
1689          * @param tablePtr
1690          * @param offsetReg
1691          */
1692         public void writeJMP(Object tablePtr, GPR offsetReg) {
1693         write2bOpcodeReg(0xFF, 0xA0, offsetReg);
1694         // effective address == disp32[reg]
1695                 writeObjectRef(tablePtr, 0, false);
1696         }
1697
1698         /**
1699          * Create a absolute jump to address in register.
1700          * 
1701          * @param reg
1702          */
1703         public final void writeJMP(GPR reg) {
1704                 testSize(reg, mode.getSize());
1705                 // Since JMP defaults to 64-bit in 64-bit mode, we give 0 as
1706                 // operand size to avoid a REX prefix.
1707                 write1bOpcodeModRR(0xff, 0, reg, 4);
1708         }
1709
1710         /**
1711          * Create a absolute jump to [reg+disp]
1712          * 
1713          * @param reg32
1714          */
1715         public final void writeJMP(GPR reg, int disp) {
1716         write2bOpcodeReg(0xFF, 0xA0, reg);
1717                 write32(disp);
1718         }
1719
1720         /**
1721          * Create a lea dstReg,[srcReg+disp]
1722          * 
1723          * @param dstReg
1724          * @param srcReg
1725          * @param disp
1726          */
1727         public final void writeLEA(GPR dstReg, GPR srcReg, int disp) {
1728                 write1bOpcodeModRM(0x8d, dstReg.getSize(), srcReg, disp, dstReg.getNr());
1729         }
1730
1731         /**
1732          * Create a lea dstReg,[srcReg+srcIdxReg*scale+disp]
1733          * 
1734          * @param dstReg
1735          * @param srcReg
1736          * @param srcIdxReg
1737          * @param scale
1738          * @param disp
1739          */
1740         public final void writeLEA(GPR dstReg, GPR srcReg, GPR srcIdxReg,
1741                         int scale, int disp) {
1742                 write1bOpcodeModRMSib(0x8d, dstReg.getSize(), srcReg, disp, dstReg
1743                                 .getNr(), scale, srcIdxReg);
1744         }
1745
1746         /**
1747          * Create a LODSD
1748          */
1749         public final void writeLODSD() {
1750                 write8(0xAD);
1751         }
1752
1753         /**
1754          * Create a LOOP label instruction. The given label must have be resolved
1755          * before!
1756          * 
1757          * @param label
1758          * @throws UnresolvedObjectRefException
1759          */
1760         public final void writeLOOP(Label label)
1761                         throws UnresolvedObjectRefException {
1762                 final ObjectRef ref = getObjectRef(label);
1763                 if (ref.isResolved()) {
1764                         write8(0xE2);
1765                         final int offset = m_used + 1;
1766                         int distance = ref.getOffset() - offset;
1767                         if (X86Utils.isByte(distance)) {
1768                                 write8(distance);
1769                         } else {
1770                                 throw new UnresolvedObjectRefException("Label " + label
1771                                                 + " is out of range (distance " + distance + ")");
1772                         }
1773                 } else {
1774                         throw new UnresolvedObjectRefException("Label " + label
1775                                         + " is not resolved");
1776                 }
1777         }
1778
1779         /**
1780          * Write a REX prefix byte if needed for ModRM and ModRR encoded opcodes.
1781          * 
1782          * @param rm
1783          * @param reg
1784          */
1785         private final void write1bOpcodeREXPrefix(int operandSize, int reg) {
1786                 int rex = 0;
1787                 if (operandSize == BITS64) {
1788                         rex |= REX_W_PREFIX;
1789                 }
1790                 if (reg > 7) {
1791                         rex |= REX_B_PREFIX;
1792                 }
1793                 if (rex != 0) {
1794                         write8(rex);
1795                 }
1796         }
1797     
1798     /**
1799      * Write a 1 byte opcode that has the register encoded in the single byte.
1800      * @param opcode1
1801      * @param reg
1802      */
1803     private final void write1bOpcodeReg(int opcode1, X86Register reg) {
1804         write1bOpcodeREXPrefix(reg.getSize(), reg.getNr());
1805         write8(opcode1 + (reg.getNr() & 7));
1806     }
1807
1808     /**
1809      * Write a 2 byte opcode that has the register encoded in the single byte.
1810      * @param opcode1
1811      * @param opcode2
1812      * @param reg
1813      */
1814     private final void write2bOpcodeReg(int opcode1, int opcode2, X86Register reg) {
1815         write1bOpcodeREXPrefix(reg.getSize(), reg.getNr());
1816         write8(opcode1);
1817         write8(opcode2 + (reg.getNr() & 7));
1818     }
1819
1820         /**
1821          * Write a REX prefix byte if needed for ModRM and ModRR encoded opcodes.
1822          * 
1823          * @param rm
1824          * @param reg
1825          */
1826         private final void writeModRMRREXPrefix(int operandSize, X86Register rm,
1827                         int reg) {
1828                 int rex = 0;
1829                 if (operandSize == BITS64) {
1830                         rex |= REX_W_PREFIX;
1831                 }
1832                 if (rm.getNr() > 7) {
1833                         rex |= REX_B_PREFIX;
1834                 }
1835                 if (reg > 7) {
1836                         rex |= REX_R_PREFIX;
1837                 }
1838                 if (rex != 0) {
1839                         write8(rex);
1840                 }
1841         }
1842
1843         /**
1844          * Write a REX prefix byte if needed.
1845          * 
1846          * @param rm
1847          * @param reg
1848          */
1849         private final void writeModRMSibREXPrefix(int operandSize, GPR base,
1850                         int reg, GPR index) {
1851                 int rex = 0;
1852                 if (operandSize == BITS64) {
1853                         rex |= REX_W_PREFIX;
1854                 }
1855                 if (base.getNr() > 7) {
1856                         rex |= REX_B_PREFIX;
1857                 }
1858                 if (reg > 7) {
1859                         rex |= REX_R_PREFIX;
1860                 }
1861                 if (index.getNr() > 7) {
1862                         rex |= REX_X_PREFIX;
1863                 }
1864                 if (rex != 0) {
1865                         write8(rex);
1866                 }
1867         }
1868
1869         /**
1870          * Write a mod-r/m byte+offset for the following addressing scheme's [rm]
1871          * disp8[rm] disp32[rm]
1872          * 
1873          * @param rm
1874          * @param disp
1875          * @param reg
1876          */
1877         private final void writeModRM(int rm, int disp, int reg) {
1878                 if ((rm < 0) || (rm > 7)) {
1879                         throw new IllegalArgumentException("rm");
1880                 }
1881                 if ((reg < 0) || (reg > 7)) {
1882                         throw new IllegalArgumentException("reg");
1883                 }
1884                 if (rm == X86Register.ESP.getNr()) {
1885                         if (X86Utils.isByte(disp)) {
1886                                 write8(0x40 | (reg << 3) | rm);
1887                                 write8(0x24);
1888                                 write8(disp);
1889                         } else {
1890                                 write8(0x80 | (reg << 3) | rm);
1891                                 write8(0x24);
1892                                 write32(disp);
1893                         }
1894                 } else {
1895                         if ((disp == 0) && (rm != X86Register.EBP.getNr())) {
1896                                 write8(0x00 | (reg << 3) | rm);
1897                         } else if (X86Utils.isByte(disp)) {
1898                                 write8(0x40 | (reg << 3) | rm);
1899                                 write8(disp);
1900                         } else {
1901                                 write8(0x80 | (reg << 3) | rm);
1902                                 write32(disp);
1903                         }
1904                 }
1905         }
1906
1907         /**
1908          * Write a 1-byte instruction followed by a mod-r/m byte+offset for the
1909          * following addressing scheme's [rm] disp8[rm] disp32[rm]
1910          * 
1911          * @param opcode
1912          * @param rm
1913          * @param disp
1914          * @param reg
1915          */
1916         private final void write1bOpcodeModRM(int opcode, int operandSize, GPR rm,
1917                         int disp, int reg) {
1918                 writeModRMRREXPrefix(operandSize, rm, reg);
1919                 write8(opcode);
1920                 writeModRM(rm.getNr() & 7, disp, reg & 7);
1921         }
1922
1923         /**
1924          * Write a 2-byte instruction followed by a mod-r/m byte+offset for the
1925          * following addressing scheme's [rm] disp8[rm] disp32[rm]
1926          * 
1927          * @param opcode
1928          * @param rm
1929          * @param disp
1930          * @param reg
1931          */
1932         private final void write2bOpcodeModRM(int opcode1, int opcode2,
1933                         int operandSize, GPR rm, int disp, int reg) {
1934                 writeModRMRREXPrefix(operandSize, rm, reg);
1935                 write8(opcode1);
1936                 write8(opcode2);
1937                 writeModRM(rm.getNr() & 7, disp, reg & 7);
1938         }
1939
1940         /**
1941          * Write a 2-byte instruction followed by a mod-r/m byte+offset for the
1942          * following addressing scheme's [rm] disp8[rm] disp32[rm]
1943          * 
1944          * @param opcode
1945          * @param rm
1946          * @param disp
1947          * @param reg
1948          */
1949         private final void write3bOpcodeModRM(int opcode1, int opcode2,
1950                         int opcode3, int operandSize, GPR rm, int disp, int reg) {
1951                 writeModRMRREXPrefix(operandSize, rm, reg);
1952                 write8(opcode1);
1953                 write8(opcode2);
1954                 write8(opcode3);
1955                 writeModRM(rm.getNr() & 7, disp, reg & 7);
1956         }
1957
1958         /**
1959          * Write a mod-r/m byte+offset+scale+index+base for the following addressing
1960          * scheme's [rm] disp8[rm] disp32[rm] To create
1961          * <code>[index*scale+disp]</code> code, set base to -1.
1962          * 
1963          * @param base
1964          * @param disp
1965          * @param reg
1966          * @param scale
1967          * @param index
1968          */
1969         private final void writeModRMSib(int base, int disp, int reg, int scale,
1970                         int index) {
1971                 if ((base < -1) || (base > 7))
1972                         throw new IllegalArgumentException("base");
1973                 if ((reg < 0) || (reg > 7))
1974                         throw new IllegalArgumentException("reg");
1975                 if ((index < 0) || (index > 7))
1976                         throw new IllegalArgumentException("index");
1977
1978                 switch (scale) {
1979                 case 1:
1980                         scale = 0;
1981                         break;
1982                 case 2:
1983                         scale = 1;
1984                         break;
1985                 case 4:
1986                         scale = 2;
1987                         break;
1988                 case 8:
1989                         scale = 3;
1990                         break;
1991                 default:
1992                         throw new IllegalArgumentException("scale");
1993                 }
1994
1995                 if (base == -1) {
1996                         write8(0x00 | (reg << 3) | 4);
1997                         write8((scale << 6) | (index << 3) | 5);
1998                         write32(disp);
1999                 } else if ((disp == 0) && (base != X86Register.EBP.getNr())) {
2000                         write8(0x00 | (reg << 3) | 4);
2001                         write8((scale << 6) | (index << 3) | base);
2002                 } else if (X86Utils.isByte(disp)) {
2003                         write8(0x40 | (reg << 3) | 4);
2004                         write8((scale << 6) | (index << 3) | base);
2005                         write8(disp);
2006                 } else {
2007                         write8(0x80 | (reg << 3) | 4);
2008                         write8((scale << 6) | (index << 3) | base);
2009                         write32(disp);
2010                 }
2011         }
2012
2013         /**
2014          * Write a 1-byte instruction followed by a mod-r/m byte+offset for the
2015          * following addressing scheme's [rm] disp8[rm] disp32[rm]
2016          * 
2017          * @param opcode
2018          * @param base
2019          * @param disp
2020          * @param reg
2021          * @param scale
2022          * @param index
2023          */
2024         private final void write1bOpcodeModRMSib(int opcode, int operandSize,
2025                         GPR base, int disp, int reg, int scale, GPR index) {
2026         testSize(base, mode.getSize());
2027         testSize(index, mode.getSize());
2028                 writeModRMSibREXPrefix(operandSize, base, reg, index);
2029                 write8(opcode);
2030                 writeModRMSib(base.getNr() & 7, disp, reg & 7, scale, index.getNr() & 7);
2031         }
2032
2033         /**
2034          * Write a mod-r/m byte for the following addressing scheme rm
2035          * 
2036          * @param rm
2037          * @param reg
2038          */
2039         private final void writeModRR(int rm, int reg) {
2040                 if ((rm < 0) || (rm > 7))
2041                         throw new IllegalArgumentException("rm");
2042                 if ((reg < 0) || (reg > 7))
2043                         throw new IllegalArgumentException("reg");
2044                 write8(0xc0 | (reg << 3) | rm);
2045         }
2046
2047         /**
2048          * Write a 1-byte instruction followed by a mod-r/m byte for the following
2049          * addressing scheme rm
2050          * 
2051          * @param opcode
2052          * @param operandSize
2053          *            Size of the operands ({@link X86Constants}.BITSxxx)
2054          * @param rm
2055          * @param reg
2056          */
2057         private final void write1bOpcodeModRR(int opcode, int operandSize, GPR rm,
2058                         int reg) {
2059                 writeModRMRREXPrefix(operandSize, rm, reg);
2060                 write8(opcode);
2061                 writeModRR(rm.getNr() & 7, reg & 7);
2062         }
2063
2064         /**
2065          * Write a 2-byte instruction followed by a mod-r/m byte for the following
2066          * addressing scheme rm
2067          * 
2068          * @param opcode
2069          * @param rm
2070          * @param reg
2071          */
2072         private final void write2bOpcodeModRR(int opcode1, int opcode2,
2073                         int operandSize, GPR rm, int reg) {
2074                 writeModRMRREXPrefix(operandSize, rm, reg);
2075                 write8(opcode1);
2076                 write8(opcode2);
2077                 writeModRR(rm.getNr() & 7, reg & 7);
2078         }
2079
2080         /**
2081          * Write a 3-byte instruction followed by a mod-r/m byte for the following
2082          * addressing scheme rm
2083          * 
2084          * @param opcode
2085          * @param rm
2086          * @param reg
2087          */
2088         private final void write3bOpcodeModRR(int opcode1, int opcode2,
2089                         int opcode3, int operandSize, X86Register rm, int reg) {
2090                 writeModRMRREXPrefix(operandSize, rm, reg);
2091                 write8(opcode1);
2092                 write8(opcode2);
2093                 write8(opcode3);
2094                 writeModRR(rm.getNr() & 7, reg & 7);
2095         }
2096
2097         /**
2098          * Create a mov [dstReg+dstDisp], <srcReg>
2099          * 
2100          * @param operandSize
2101          * @param dstReg
2102          * @param dstDisp
2103          * @param srcReg
2104          */
2105         public final void writeMOV(int operandSize, GPR dstReg, int dstDisp,
2106                         GPR srcReg) {
2107                 testDst(dstReg, dstDisp);
2108                 final int opcode;
2109                 switch (operandSize) {
2110                 case X86Constants.BITS8:
2111                         opcode = 0x88;
2112                         break;
2113                 case X86Constants.BITS16:
2114                         opcode = 0x89;
2115                         write8(OSIZE_PREFIX);
2116                         break;
2117                 case X86Constants.BITS32:
2118                 case X86Constants.BITS64:
2119                         opcode = 0x89;
2120                         break;
2121                 default:
2122                         throw new IllegalArgumentException("Invalid operandSize "
2123                                         + operandSize);
2124                 }
2125                 write1bOpcodeModRM(opcode, operandSize, dstReg, dstDisp, srcReg.getNr());
2126         }
2127
2128         /**
2129          * Create a mov <dstReg>, <srcReg>
2130          * 
2131          * @param operandSize
2132          * @param dstReg
2133          * @param srcReg
2134          */
2135         public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg) {
2136                 final int opcode;
2137                 switch (operandSize) {
2138                 case X86Constants.BITS8:
2139                         testSuitableForBits8(dstReg);
2140                         opcode = 0x88;
2141                         break;
2142                 case X86Constants.BITS16:
2143                         opcode = 0x89;
2144                         write8(OSIZE_PREFIX);
2145                         break;
2146                 case X86Constants.BITS32:
2147                 case X86Constants.BITS64:
2148                         opcode = 0x89;
2149                         break;
2150                 default:
2151                         throw new IllegalArgumentException("Invalid operandSize "
2152                                         + operandSize);
2153                 }
2154                 write1bOpcodeModRR(opcode, operandSize, dstReg, srcReg.getNr());
2155         }
2156
2157         /**
2158          * Create a mov dstReg, [srcReg+srcDisp]
2159          * 
2160          * @param operandSize
2161          * @param dstReg
2162          * @param srcReg
2163          * @param srcDisp
2164          */
2165         public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg,
2166                         int srcDisp) {
2167                 final int opcode;
2168                 switch (operandSize) {
2169                 case X86Constants.BITS8:
2170                         testSuitableForBits8(dstReg);
2171                         opcode = 0x8a;
2172                         break;
2173                 case X86Constants.BITS16:
2174                         opcode = 0x8b;
2175                         write8(OSIZE_PREFIX);
2176                         break;
2177                 case X86Constants.BITS32:
2178                 case X86Constants.BITS64:
2179                         opcode = 0x8b;
2180                         break;
2181                 default:
2182                         throw new IllegalArgumentException("Invalid operandSize "
2183                                         + operandSize);
2184                 }
2185                 write1bOpcodeModRM(opcode, operandSize, srcReg, srcDisp, dstReg.getNr());
2186         }
2187
2188         /**
2189          * Create a mov [dstReg+dstIdxReg*scale+dstDisp], <srcReg>
2190          * 
2191          * @param operandSize
2192          * @param dstReg
2193          * @param dstIdxReg
2194          * @param scale
2195          * @param dstDisp
2196          * @param srcReg
2197          */
2198         public final void writeMOV(int operandSize, GPR dstReg, GPR dstIdxReg,
2199                         int scale, int dstDisp, GPR srcReg) {
2200                 final int opcode;
2201                 switch (operandSize) {
2202                 case X86Constants.BITS8:
2203                         opcode = 0x88;
2204                         break;
2205                 case X86Constants.BITS16:
2206                         opcode = 0x89;
2207                         write8(OSIZE_PREFIX);
2208                         break;
2209                 case X86Constants.BITS32:
2210                 case X86Constants.BITS64:
2211                         opcode = 0x89;
2212                         break;
2213                 default:
2214                         throw new IllegalArgumentException("Invalid operandSize "
2215                                         + operandSize);
2216                 }
2217                 write1bOpcodeModRMSib(opcode, operandSize, dstReg, dstDisp, srcReg
2218                                 .getNr(), scale, dstIdxReg);
2219         }
2220
2221         /**
2222          * Create a mov dstReg, [srcReg+srcIdxReg*scale+srcDisp]
2223          * 
2224          * @param operandSize
2225          * @param dstReg
2226          * @param srcReg
2227          * @param srcIdxReg
2228          * @param scale
2229          * @param srcDisp
2230          */
2231         public final void writeMOV(int operandSize, GPR dstReg, GPR srcReg,
2232                         GPR srcIdxReg, int scale, int srcDisp) {
2233                 final int opcode;
2234                 switch (operandSize) {
2235                 case X86Constants.BITS8:
2236                         testSuitableForBits8(dstReg);
2237                         opcode = 0x8a;
2238                         break;
2239                 case X86Constants.BITS16:
2240                         opcode = 0x8b;
2241                         write8(OSIZE_PREFIX);
2242                         break;
2243                 case X86Constants.BITS32:
2244                 case X86Constants.BITS64:
2245                         opcode = 0x8b;
2246                         break;
2247                 default:
2248                         throw new IllegalArgumentException("Invalid operandSize "
2249                                         + operandSize);
2250                 }
2251                 write1bOpcodeModRMSib(opcode, operandSize, srcReg, srcDisp, dstReg
2252                                 .getNr(), scale, srcIdxReg);
2253         }
2254
2255         /**
2256          * Create a MOV reg,imm32 or MOV reg,imm64
2257          * 
2258          * @param dstReg
2259          * @param imm32
2260          */
2261         public final void writeMOV_Const(GPR dstReg, int imm32) {
2262                 testSize(dstReg, BITS32 | BITS64);
2263                 if (dstReg.getSize() == BITS32) {
2264             write1bOpcodeReg(0xB8, dstReg);
2265                         write32(imm32);
2266                 } else {
2267                         writeMOV_Const(dstReg, (long) imm32);
2268                 }
2269         }
2270
2271         /**
2272          * Create a MOV reg,imm64 depending on the reg size. Only valid in 64-bit
2273          * mode.
2274          * 
2275          * @param dstReg
2276          * @param imm64
2277          * @throws InvalidOpcodeException
2278          *             In 32-bit modes.
2279          */
2280         public void writeMOV_Const(GPR dstReg, long imm64)
2281                         throws InvalidOpcodeException {
2282                 if (!code64) {
2283                         throw new InvalidOpcodeException();
2284                 }
2285                 testSize(dstReg, BITS64);
2286         write1bOpcodeReg(0xB8, dstReg);
2287                 write64(imm64);
2288         }
2289
2290         /**
2291          * Create a mov [destReg+destDisp], imm32
2292          * 
2293          * @param destReg
2294          * @param destDisp
2295          * @param imm32
2296          */
2297         public final void writeMOV_Const(int operandSize, GPR destReg,
2298                         int destDisp, int imm32) {
2299                 testOperandSize(operandSize, BITS32 | BITS64);
2300                 write1bOpcodeModRM(0xC7, operandSize, destReg, destDisp, 0);
2301                 write32(imm32);
2302         }
2303
2304         /**
2305          * Create a mov reg, label
2306          * 
2307          * @param dstReg
2308          * @param label
2309          */
2310         public final void writeMOV_Const(GPR dstReg, Object label) {
2311                 testOperandSize(dstReg.getSize(), mode.getSize());
2312         write1bOpcodeReg(0xB8, dstReg);
2313                 writeObjectRef(label, 0, false);
2314         }
2315
2316         /**
2317          * Create a mov size [destReg+dstIdxReg*scale+destDisp], imm32
2318          * 
2319          * @param dstReg
2320          * @param dstDisp
2321          * @param imm32
2322          */
2323         public void writeMOV_Const(int operandSize, GPR dstReg, GPR dstIdxReg,
2324                         int scale, int dstDisp, int imm32) {
2325                 write1bOpcodeModRMSib(0xC7, operandSize, dstReg, dstDisp, 0, scale,
2326                                 dstIdxReg);
2327                 write32(imm32);
2328         }
2329
2330         /**
2331          * Create a movsd [dst+dstDisp],src
2332          * 
2333          * @param dst
2334          * @param src
2335          */
2336         public void writeMOVSD(X86Register.GPR dst, int dstDisp, X86Register.XMM src) {
2337                 write3bOpcodeModRM(0xF2, 0x0F, 0x11, 0, dst, dstDisp, src.getNr());
2338         }
2339
2340         /**
2341          * Create a movsd dst,[src+srcDisp]
2342          * 
2343          * @param dst
2344          * @param src
2345          */
2346         public void writeMOVSD(X86Register.XMM dst, X86Register.GPR src, int srcDisp) {
2347                 write3bOpcodeModRM(0xF2, 0x0F, 0x10, 0, src, srcDisp, dst.getNr());
2348         }
2349
2350         /**
2351          * Create a movsd dst,src
2352          * 
2353          * @param dst
2354          * @param src
2355          */
2356         public void writeMOVSD(X86Register.XMM dst, X86Register.XMM src) {
2357                 write3bOpcodeModRR(0xF2, 0x0F, 0x10, 0, dst, src.getNr());
2358         }
2359
2360         /**
2361          * Create a movss [dst+dstDisp],src
2362          * 
2363          * @param dst
2364          * @param src
2365          */
2366         public void writeMOVSS(X86Register.GPR dst, int dstDisp, X86Register.XMM src) {
2367                 write3bOpcodeModRM(0xF3, 0x0F, 0x11, 0, dst, dstDisp, src.getNr());
2368         }
2369
2370         /**
2371          * Create a movss dst,[src+srcDisp]
2372          * 
2373          * @param dst
2374          * @param src
2375          */
2376         public void writeMOVSS(X86Register.XMM dst, X86Register.GPR src, int srcDisp) {
2377                 write3bOpcodeModRM(0xF3, 0x0F, 0x10, 0, src, srcDisp, dst.getNr());
2378         }
2379
2380         /**
2381          * Create a movss dst,src
2382          * 
2383          * @param dst
2384          * @param src
2385          */
2386         public void writeMOVSS(X86Register.XMM dst, X86Register.XMM src) {
2387                 write3bOpcodeModRR(0xF3, 0x0F, 0x10, 0, dst, src.getNr());
2388         }
2389
2390         /**
2391          * Create a movsx <dstReg>, <srcReg>
2392          * 
2393          * @param dstReg
2394          * @param srcReg
2395          * @param srcSize
2396          */
2397         public final void writeMOVSX(GPR dstReg, GPR srcReg, int srcSize) {
2398                 if (srcSize == X86Constants.BITS8) {
2399                         testSuitableForBits8(dstReg);
2400                         write2bOpcodeModRR(0x0F, 0xBE, dstReg.getSize(), srcReg, dstReg
2401                                         .getNr());
2402                 } else if (srcSize == X86Constants.BITS16) {
2403                         write2bOpcodeModRR(0x0F, 0xBF, dstReg.getSize(), srcReg, dstReg
2404                                         .getNr());
2405                 } else {
2406                         throw new IllegalArgumentException("Unknown srcSize " + srcSize);
2407                 }
2408         }
2409
2410         public void writeMOVSX(GPR dstReg, GPR srcReg, int srcDisp, int srcSize) {
2411                 if (srcSize == X86Constants.BITS8) {
2412                         testSuitableForBits8(dstReg);
2413                         write2bOpcodeModRM(0x0F, 0xBE, dstReg.getSize(), srcReg, srcDisp,
2414                                         dstReg.getNr());
2415                 } else if (srcSize == X86Constants.BITS16) {
2416                         write2bOpcodeModRM(0x0F, 0xBF, dstReg.getSize(), srcReg, srcDisp,
2417                                         dstReg.getNr());
2418                 } else {
2419                         throw new IllegalArgumentException("Unknown srcSize " + srcSize);
2420                 }
2421         }
2422
2423         /**
2424          * Create a movsxd dstReg, srcReg. Sign extends the srcReg to dstReg. Only
2425          * valid in 64-bit mode.
2426          * 
2427          * @param dstReg
2428          * @param srcReg
2429          */
2430         public void writeMOVSXD(GPR64 dstReg, GPR32 srcReg)
2431                         throws InvalidOpcodeException {
2432                 if (!code64) {
2433                         throw new InvalidOpcodeException();
2434                 }
2435                 write1bOpcodeModRR(0x63, dstReg.getSize(), srcReg, dstReg.getNr());
2436         }
2437
2438         /**
2439          * Create a movzx <dstReg>, <srcReg>
2440          * 
2441          * @param dstReg
2442          * @param srcReg
2443          * @param srcSize
2444          */
2445         public final void writeMOVZX(GPR dstReg, GPR srcReg, int srcSize) {
2446                 if (srcSize == X86Constants.BITS8) {
2447                         testSuitableForBits8(dstReg);
2448                         write2bOpcodeModRR(0x0F, 0xB6, dstReg.getSize(), srcReg, dstReg
2449                                         .getNr());
2450                 } else if (srcSize == X86Constants.BITS16) {
2451                         write2bOpcodeModRR(0x0F, 0xB7, dstReg.getSize(), srcReg, dstReg
2452                                         .getNr());
2453                 } else {
2454                         throw new IllegalArgumentException("Unknown srcSize " + srcSize);
2455                 }
2456         }
2457
2458         public void writeMOVZX(GPR dstReg, GPR srcReg, int srcDisp, int srcSize) {
2459                 if (srcSize == X86Constants.BITS8) {
2460                         testSuitableForBits8(dstReg);
2461                         write2bOpcodeModRM(0x0F, 0xB6, dstReg.getSize(), srcReg, srcDisp,
2462                                         dstReg.getNr());
2463                 } else if (srcSize == X86Constants.BITS16) {
2464                         write2bOpcodeModRM(0x0F, 0xB7, dstReg.getSize(), srcReg, srcDisp,
2465                                         dstReg.getNr());
2466                 } else {
2467                         throw new IllegalArgumentException("Unknown srcSize " + srcSize);
2468                 }
2469         }
2470
2471         /**
2472          * Create a mul eax, srcReg
2473          * 
2474          * @param srcReg
2475          */
2476         public final void writeMUL_EAX(GPR srcReg) {
2477                 write1bOpcodeModRR(0xF7, srcReg.getSize(), srcReg, 4);
2478         }
2479
2480         /**
2481          * Create a neg dstReg
2482          * 
2483          * @param dstReg
2484          */
2485         public final void writeNEG(GPR dstReg) {
2486                 write1bOpcodeModRR(0xf7, dstReg.getSize(), dstReg, 3);
2487         }
2488
2489         /**
2490          * Create a neg dword [dstReg+dstDisp]
2491          * 
2492          * @param dstReg
2493          * @param dstDisp
2494          */
2495         public final void writeNEG(int operandSize, GPR dstReg, int dstDisp) {
2496                 testOperandSize(operandSize, BITS32 | BITS64);
2497                 write1bOpcodeModRM(0xf7, operandSize, dstReg, dstDisp, 3);
2498         }
2499
2500         /**
2501          * Create a nop
2502          */
2503         public final void writeNOP() {
2504                 write8(0x90);
2505         }
2506
2507         /**
2508          * Create a not dstReg
2509          * 
2510          * @param dstReg
2511          */
2512         public final void writeNOT(GPR dstReg) {
2513                 write1bOpcodeModRR(0xf7, dstReg.getSize(), dstReg, 2);
2514         }
2515
2516         /**
2517          * Create a not dword [dstReg+dstDisp]
2518          * 
2519          * @param dstReg
2520          * @param dstDisp
2521          */
2522         public final void writeNOT(int operandSize, GPR dstReg, int dstDisp) {
2523                 testOperandSize(operandSize, BITS32 | BITS64);
2524                 write1bOpcodeModRM(0xf7, operandSize, dstReg, dstDisp, 2);
2525         }
2526
2527         /**
2528          * Create 32-bit reference to an absolute address like: dd label
2529          * 
2530          * @param object
2531          */
2532         public final void writeObjectRef(Object object) {
2533                 writeObjectRef(object, 0, false);
2534         }
2535
2536         /**
2537          * Create 32-bit reference to an absolute address like: dd label
2538          * 
2539          * @param object
2540          * @param offset
2541          * @param rawAddress
2542          *            If true, object is a raw address, not a normal object.
2543          */
2544         private final void writeObjectRef(Object object, int offset,
2545                         boolean rawAddress) {
2546                 if (object == null) {
2547                         writeWord(offset);
2548                 } else if (rawAddress) {
2549                         if (mode.is32()) {
2550                                 write32(resolver.addressOf32(object) + offset);
2551                         } else {
2552                                 write64(resolver.addressOf64(object) + offset);
2553                         }
2554                 } else if ((resolver != null) && (!(object instanceof Label))) {
2555                         if (mode.is32()) {
2556                                 write32(resolver.addressOf32(object) + offset);
2557                         } else {
2558                                 write64(resolver.addressOf64(object) + offset);
2559                         }
2560                 } else {
2561                         final X86ObjectRef ref = (X86ObjectRef) getObjectRef(object);
2562                         if (ref.isResolved()) {
2563                                 try {
2564                                         //System.out.println("Resolved offset " + ref.getOffset());
2565                                         writeWord(ref.getOffset() + baseAddr + offset);
2566                                 } catch (UnresolvedObjectRefException e) {
2567                                         throw new RuntimeException(e);
2568                                 }
2569                         } else {
2570                                 //System.out.println("Unresolved");
2571                                 ref.addUnresolvedLink(m_used, getWordSize());
2572                                 writeWord(-(baseAddr + offset));
2573                         }
2574                 }
2575         }
2576
2577         /**
2578          * 
2579          * @param dstReg
2580          * @param imm32
2581          */
2582         public void writeOR(GPR dstReg, int imm32) {
2583                 if (X86Utils.isByte(imm32)) {
2584                         write1bOpcodeModRR(0x83, dstReg.getSize(), dstReg, 1);
2585                         write8(imm32);
2586                 } else {
2587                         write1bOpcodeModRR(0x81, dstReg.getSize(), dstReg, 1);
2588                         write32(imm32);
2589                 }
2590         }
2591
2592         /**
2593          * 
2594          * @param dstReg
2595          * @param dstDisp
2596          * @param imm32
2597          */
2598         public void writeOR(int operandSize, GPR dstReg, int dstDisp, int imm32) {
2599                 if (X86Utils.isByte(imm32)) {
2600                         write1bOpcodeModRM(0x83, operandSize, dstReg, dstDisp, 1);
2601                         write8(imm32);
2602                 } else {
2603                         write1bOpcodeModRM(0x81, operandSize, dstReg, dstDisp, 1);
2604                         write32(imm32);
2605                 }
2606         }
2607
2608         /**
2609          * Create a OR [dstReg+dstDisp], srcReg
2610          * 
2611          * @param dstReg
2612          * @param dstDisp
2613          * @param srcReg
2614          */
2615         public final void writeOR(GPR dstReg, int dstDisp, GPR srcReg) {
2616                 write1bOpcodeModRM(0x09, srcReg.getSize(), dstReg, dstDisp, srcReg
2617                                 .getNr());
2618         }
2619
2620         /**
2621          * Create a OR dstReg, srcReg
2622          * 
2623          * @param dstReg
2624          * @param srcReg
2625          */
2626         public final void writeOR(GPR dstReg, GPR srcReg) {
2627                 write1bOpcodeModRR(0x09, dstReg.getSize(), dstReg, srcReg.getNr());
2628         }
2629
2630         /**
2631          * Create a OR dstReg, [srcReg+srcDisp]
2632          * 
2633          * @param dstReg
2634          * @param srcReg
2635          * @param srcDisp
2636          */
2637         public void writeOR(GPR dstReg, GPR srcReg, int srcDisp) {
2638                 write1bOpcodeModRM(0x0B, dstReg.getSize(), srcReg, srcDisp, dstReg
2639                                 .getNr());
2640         }
2641
2642         /**
2643          * Create a pop reg32
2644          * 
2645          * @param dstReg
2646          */
2647         public final void writePOP(GPR dstReg) {
2648         write1bOpcodeReg(0x58, dstReg);
2649         }
2650
2651         /**
2652          * Create a pop dword [reg32+disp]
2653          * 
2654          * @param dstReg
2655          * @param dstDisp
2656          */
2657         public final void writePOP(GPR dstReg, int dstDisp) {
2658                 // POP has no encoding for 32-bit in 64-bit mode, so give
2659                 // operand size 0 to avoid a REX prefix.
2660                 write1bOpcodeModRM(0x8f, 0, dstReg, dstDisp, 0);
2661         }
2662
2663         /**
2664          * @see org.jnode.assembler.x86.X86Assembler#writePOPA()
2665          */
2666         public void writePOPA() {
2667                 if (code64) {
2668                         throw new InvalidOpcodeException();
2669                 }
2670                 write8(0x61);
2671         }
2672
2673         /**
2674          * @see org.jnode.assembler.x86.X86Assembler#writePrefix(int)
2675          */
2676         public void writePrefix(int prefix) {
2677                 write8(prefix);
2678         }
2679
2680         /**
2681          * Create a push dword imm32
2682          * 
2683          * @param imm32
2684          * @return The ofset of the start of the instruction.
2685          */
2686         public final int writePUSH(int imm32) {
2687                 final int rc = m_used;
2688                 write8(0x68); // PUSH imm32
2689                 write32(imm32);
2690                 return rc;
2691         }
2692
2693         /**
2694          * Create a push srcReg
2695          * 
2696          * @param srcReg
2697          * @return The ofset of the start of the instruction.
2698          */
2699         public final int writePUSH(GPR srcReg) {
2700         final int rc = m_used;
2701         write1bOpcodeReg(0x50, srcReg);
2702                 return rc;
2703         }
2704
2705         /**
2706          * Create a push d/qword [srcReg+srcDisp]
2707          * 
2708          * @param srcReg
2709          * @param srcDisp
2710          * @return The ofset of the start of the instruction.
2711          */
2712         public final int writePUSH(GPR srcReg, int srcDisp) {
2713                 // PUSH has not encoding for 32-bit in 64-bit mode, so give
2714                 // operand size 0 to avoid a REX prefix.
2715                 final int rc = m_used;
2716                 write1bOpcodeModRM(0xFF, 0, srcReg, srcDisp, 6);
2717                 return rc;
2718         }
2719
2720         /**
2721          * Create a push d/qword [baseReg+indexReg*scale+disp]
2722          * 
2723          * @param srcBaseReg
2724          * @param srcIndexReg
2725          * @param srcScale
2726          * @param srcDisp
2727          * @return The ofset of the start of the instruction.
2728          */
2729         public final int writePUSH(GPR srcBaseReg, GPR srcIndexReg, int srcScale,
2730                         int srcDisp) {
2731                 // PUSH has not encoding for 32-bit in 64-bit mode, so give
2732                 // operand size 0 to avoid a REX prefix.
2733                 final int rc = m_used;
2734                 write1bOpcodeModRMSib(0xFF, 0, srcBaseReg, srcDisp, 6, srcScale,
2735                                 srcIndexReg);
2736                 return rc;
2737         }
2738
2739         /**
2740          * Create a push dword <object>
2741          * 
2742          * @param objRef
2743          * @return The offset of the start of the instruction.
2744          */
2745         public final int writePUSH_Const(Object objRef) {
2746         if (code64) {