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 + -
显示快捷键?