x86stream.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 2,052 行 · 第 1/4 页

JAVA
2,052
字号
/**
 * $Id: X86Stream.java,v 1.16 2004/02/26 10:33:49 epr Exp $
 */

package org.jnode.assembler.x86;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import org.jnode.assembler.BootImageNativeStream;
import org.jnode.assembler.Label;
import org.jnode.assembler.NativeStream;
import org.jnode.assembler.ObjectResolver;
import org.jnode.assembler.UnresolvedObjectRefException;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;
import org.jnode.vm.classmgr.VmClassType;
import org.jnode.vm.classmgr.VmType;
import org.jnode.vm.x86.X86CpuID;

public class X86Stream extends AbstractX86Stream implements X86Constants,
        BootImageNativeStream {

    public static final class Key {

        private final Object key;

        public Key(Object key) {
            this.key = key;
        }

        /**
         * @param obj
         * @see java.lang.Object#equals(java.lang.Object)
         * @return True if obj is equal to this, false otherwise
         */
        public final boolean equals(Object obj) {
            /*
             * if (!(obj instanceof Key)) { return false;
             */
            obj = ((Key) obj).key;
            if (this.key instanceof Label) {
                return key.equals(obj);
            } else {
                return (obj == this.key);
            }
        }

        /**
         * @see java.lang.Object#hashCode()
         * @return The hashcode
         */
        public final int hashCode() {
            return key.hashCode();
        }

    }

    public class X86ObjectInfo extends NativeStream.ObjectInfo {

        private int m_objptr;

        X86ObjectInfo() {
            m_objptr = getLength();
        }

        /**
         * Mark the current location as the end of this object end fixup the
         * objectheader.
         */
        public void markEnd() {
            if (!inObject) { throw new RuntimeException("inObject == false"); }
            if (m_objptr == -1) { throw new RuntimeException(
                    "markEnd has already been called"); }
            align(ObjectLayout.OBJECT_ALIGN);
            int size = getLength() - m_objptr;
            set32(m_objptr - 12, size);
            m_objptr = -1;
            inObject = false;
        }
    }

    public class X86ObjectRef extends NativeStream.ObjectRef {

        private int dataOffset;

        private boolean isPublic;

        private boolean isRelJump;

        private LinkedList unresolvedLinks; // Array of data_offsets where

        public X86ObjectRef(Object object) {
            super(object);
            this.dataOffset = -1;
            this.unresolvedLinks = null;
            this.isPublic = false;
            this.isRelJump = false;
        }

        public void addUnresolvedLink(int offset) {
            if (unresolvedLinks == null) {
                unresolvedLinks = new LinkedList();
            }
            unresolvedLinks.add(new Integer(offset));
        }

        public int getOffset() {
            return dataOffset;
        }

        public int[] getUnresolvedOffsets() {
            int cnt = unresolvedLinks.size();
            int[] offsets = new int[ cnt];
            int ofs = 0;
            for (Iterator i = unresolvedLinks.iterator(); i.hasNext(); ofs++) {
                offsets[ ofs] = ((Integer) i.next()).intValue();
            }
            return offsets;
        }

        public boolean isPublic() {
            return isPublic;
        }

        public boolean isRelJump() {
            return isRelJump;
        }

        public boolean isResolved() {
            return (dataOffset != -1);
        }

        public void setOffset(int offset) {
            if (this.dataOffset != -1) {
                if ("".equals(getObject().toString())) { return; }
                throw new RuntimeException(
                        "Offset is already set. Duplicate labels? ("
                                + getObject() + ")");
            }
            this.dataOffset = offset;
            if (unresolvedLinks != null) {
                // Link all unresolved links
                for (Iterator i = unresolvedLinks.iterator(); i.hasNext();) {
                    final int addr = ((Integer) i.next()).intValue();
                    final int distance = offset - get32(addr);
                    if (isRelJump() && (distance == 0)) {
                        if (get8(addr - 1) == 0xe9) // JMP
                        {
                            set8(addr - 1, 0x90); // NOP
                            set32(addr, 0x90909090); // 4 NOP's
                        } else if (get8(addr - 2) == 0x0f) // Jcc
                        {
                            set8(addr - 2, 0x90);
                            set8(addr - 1, 0x90);
                            set32(addr, 0x90909090); // 4 NOP's
                        } else {
                            set32(addr, distance);
                        }
                    } else {
                        set32(addr, distance);
                    }
                }
                unresolvedLinks = null;
            }
        }

        public void setPublic() {
            isPublic = true;
        }

        public void setRelJump() {
            isRelJump = true;
        }

        /**
         * Link this objectref to the given objectref. That is, the offset of
         * this objectref will be set to the offset of the given objectref.
         * 
         * @param objectRef
         * @throws UnresolvedObjectRefException
         *             The given objectref is not resolved.
         */
        public void link(ObjectRef objectRef)
                throws UnresolvedObjectRefException {
            if (!objectRef.isResolved()) { throw new UnresolvedObjectRefException(
                    objectRef.getObject().toString()); }
            setOffset(objectRef.getOffset());
        }
    }

    private final int baseAddr;

    private byte[] m_data;

    private int dataLength;

    private int m_used;

    private Map objectRefs; // Integer(labelnr),Integer(offset)

    private ObjectResolver resolver;

    private final int initialObjectRefsCapacity;

    boolean inObject;

    private int growCount;

    private final int growSize;

    private final boolean haveCMOV;

    public X86Stream(X86CpuID cpuId, int baseAddr) {
        this(cpuId, baseAddr, 1024, 128, 1024);
    }

    public X86Stream(X86CpuID cpuId, int baseAddr,
            int initialObjectRefsCapacity, int initialSize, int growSize) {
        super(cpuId);
        this.m_data = new byte[ initialSize];
        this.m_used = 0;
        this.baseAddr = baseAddr;
        this.inObject = false;
        this.initialObjectRefsCapacity = initialObjectRefsCapacity;
        this.growSize = growSize;
        this.haveCMOV = cpuId.hasFeature(X86CpuID.FEAT_CMOV);
    }

    /**
     * Remove all data and references.
     */
    public void clear() {
        this.m_data = new byte[0];
        this.m_used = 0;
        this.objectRefs.clear();
    }
    
    /**
     * Align on a given value
     * 
     * @param value
     * @return The number of bytes needed to align.
     */
    public final int align(int value) {
        int count = 0;
        while ((getLength() % value) != 0) {
            write8(0x90); // Nop
            count++;
        }
        return count;
    }

    private final void ensureSize(int extra) {
        if (m_used + extra >= dataLength) {
            int newLen;
            byte[] newArr;
            if (extra > growSize) {
                newLen = dataLength + extra;
            } else {
                newLen = dataLength + growSize;
            }
            newArr = new byte[ newLen];
            System.arraycopy(m_data, 0, newArr, 0, m_used);
            m_data = newArr;
            dataLength = newLen;
            growCount++;
            //System.out.println("Growing stream buffer to " + newLen);
        }
    }

    public final int get32(int offset) {
        int v1 = m_data[ offset++];
        int v2 = m_data[ offset++];
        int v3 = m_data[ offset++];
        int v4 = m_data[ offset];
        return (v1 & 0xFF) | ((v2 & 0xFF) << 8) | ((v3 & 0xFF) << 16)
                | ((v4 & 0xFF) << 24);
    }

    public final int get8(int offset) {
        return (m_data[ offset] & 0xFF);
    }

    /**
     * Returns the base address.
     * 
     * @return long
     */
    public final long getBaseAddr() {
        return baseAddr;
    }

    /**
     * Return the actual bytes. This array may be longer then getLength() *
     * 
     * @return The actual bytes
     */
    public final byte[] getBytes() {
        return m_data;
    }

    /**
     * Get the length in bytes of valid data
     * 
     * @return the length of valid data
     */
    public final int getLength() {
        return m_used;
    }

    /**
     * Remove count bytes from the end of the generated stream.
     * 
     * @param count
     */
    public void trim(int count) {
        if ((count < 0) || (count > m_used)) { throw new IllegalArgumentException(
                "Invalid count value " + count); }
        m_used -= count;
    }

    /**
     * Gets an objectref for a given object.
     * 
     * @param keyObj
     * @return ObjectRef
     */
    public final ObjectRef getObjectRef(Object keyObj) {
        if (keyObj == null) { throw new NullPointerException(
                "Key cannot be null"); }
        if (objectRefs == null) {
            objectRefs = new HashMap(initialObjectRefsCapacity);
        }
        Key key = new Key(keyObj);
        ObjectRef ref = (ObjectRef) objectRefs.get(key);
        if (ref != null) { return ref; }
        ref = new X86ObjectRef(keyObj);
        objectRefs.put(key, ref);
        return ref;
    }

    /**
     * Gets all references of objects as instanceof ObjectRef
     * 
     * @return Collection
     */
    public final Collection getObjectRefs() {
        if (objectRefs == null) {
            objectRefs = new HashMap(initialObjectRefsCapacity);
        }
        return objectRefs.values();
    }

    public final int getObjectRefsCount() {
        if (objectRefs != null) {
            return objectRefs.size();
        } else {
            return 0;
        }
    }

    /**
     * @return ObjectResolver
     */
    public final ObjectResolver getResolver() {
        return resolver;
    }

    /**
     * Gets all unresolved references of objects as instanceof ObjectRef
     * 
     * @return Collection
     */
    public final Collection getUnresolvedObjectRefs() {
        final Collection coll = getObjectRefs();
        final LinkedList result = new LinkedList();
        for (Iterator i = coll.iterator(); i.hasNext();) {
            final ObjectRef ref = (ObjectRef) i.next();
            if (!ref.isResolved()) {
                if (!(ref.getObject() instanceof Label)) {
                    result.add(ref);
                }
            }
        }
        System.out.println("getUnresolvedObjectsRefs: count=" + result.size());
        return result;
    }

    /**
     * Are there unresolved references?
     * 
     * @return True if there are unresolved references, false otherwise
     */
    public final boolean hasUnresolvedObjectRefs() {
        final Collection coll = getObjectRefs();
        for (Iterator i = coll.iterator(); i.hasNext();) {
            final ObjectRef ref = (ObjectRef) i.next();
            if (!ref.isResolved()) {
                if (!(ref.getObject() instanceof Label)) { return true; }
            }
        }
        return false;
    }

    public final void set32(int offset, int v32) {
        m_data[ offset++] = (byte) (v32 & 0xFF);
        m_data[ offset++] = (byte) ((v32 >> 8) & 0xFF);
        m_data[ offset++] = (byte) ((v32 >> 16) & 0xFF);
        m_data[ offset++] = (byte) ((v32 >> 24) & 0xFF);
    }

    public final void set8(int offset, int v8) {
        m_data[ offset] = (byte) v8;
    }

    public final ObjectRef setObjectRef(Object label) {
        X86ObjectRef ref = (X86ObjectRef) getObjectRef(label);
        ref.setOffset(m_used);
        return ref;
    }

    /**
     * Sets the resolver.
     * 
     * @param resolver
     *            The resolver to set
     */
    public void setResolver(ObjectResolver resolver) {
        this.resolver = resolver;
    }

    public final void write(byte[] data, int ofs, int len) {
        /*
         * if (!inObject) { throw new IllegalArgumentException("Cannot write
         * out of an object");
         */
        ensureSize(len);
        System.arraycopy(data, ofs, m_data, m_used, len);
        m_used += len;
    }

    public final void write16(int v16) {
        if (!inObject) { throw new IllegalArgumentException(
                "Cannot write out of an object"); }
        ensureSize(2);
        m_data[ m_used++] = (byte) (v16 & 0xFF);
        m_data[ m_used++] = (byte) ((v16 >> 8) & 0xFF);
    }

    public final void write32(int v32) {
        /*
         * if (!inObject) { throw new IllegalArgumentException("Cannot write
         * out of an object");
         */
        ensureSize(4);
        m_data[ m_used++] = (byte) (v32 & 0xFF);
        m_data[ m_used++] = (byte) ((v32 >> 8) & 0xFF);
        m_data[ m_used++] = (byte) ((v32 >> 16) & 0xFF);
        m_data[ m_used++] = (byte) ((v32 >> 24) & 0xFF);
    }

    public final void write64(long v64) {
        if (!inObject) { throw new IllegalArgumentException(
                "Cannot write out of an object"); }
        write32((int) (v64 & 0xFFFFFFFF)); // lsb
        write32((int) ((v64 >>> 32) & 0xFFFFFFFF)); // msb
    }

    /**
     * Write an 8-bit unsigned byte.
     * 
     * @param v8
     */
    public final void write8(int v8) {
        ensureSize(1);
        m_data[ m_used++] = (byte) (v8 & 0xFF);
    }

    /**
     * @see org.jnode.assembler.x86.AbstractX86Stream#writePrefix(int)
     */
    public void writePrefix(int prefix) {
        write8(prefix);
    }

    /**
     * Create a ADD dstReg, srcReg
     * 
     * @param dstReg
     * @param srcReg
     */
    public final void writeADD(Register dstReg, Register srcReg) {
        writeModRR(0x01, dstReg.getNr(), srcReg.getNr());
    }

    /**
     * Create a ADD [dstReg+dstDisp], <srcReg>
     * 
     * @param dstReg
     * @param dstDisp
     * @param srcReg
     */
    public final void writeADD(Register dstReg, int dstDisp, Register srcReg) {
        writeModRM(0x01, dstReg.getNr(), dstDisp, srcReg.getNr());
    }

    /**

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?