From: <mic...@us...> - 2007-05-08 16:38:21
|
Revision: 106 http://svn.sourceforge.net/pearcolator/?rev=106&view=rev Author: michael_baer Date: 2007-05-08 09:38:23 -0700 (Tue, 08 May 2007) Log Message: ----------- Intermediate checkin of halfway working runtime linking. Modified Paths: -------------- src/org/binarytranslator/DBT.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/memory/DebugMemory.java Added Paths: ----------- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java Removed Paths: ------------- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java Modified: src/org/binarytranslator/DBT.java =================================================================== --- src/org/binarytranslator/DBT.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/DBT.java 2007-05-08 16:38:23 UTC (rev 106) @@ -17,7 +17,7 @@ */ public final class DBT { /** Should the following assertion be checked? */ - public static final boolean VerifyAssertions = VM.VerifyAssertions; + public static final boolean VerifyAssertions = true; /** * Assert the following condition is true, if false then fail with stack trace @@ -27,9 +27,11 @@ if (!VerifyAssertions) { // Checking an assertion in a production build is a bad idea fail("Assertion checked when assertions should be disabled.\n" - + "Please guard the assertion with DBT.VerifyAssertions"); + + "Please guard the assertion with DBT.VerifyAssertions."); } else { - VM._assert(cond); + //VM._assert(cond); + if (!cond) + throw new RuntimeException("Assertion failed."); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/Main.java 2007-05-08 16:38:23 UTC (rev 106) @@ -106,7 +106,7 @@ }*/ controller = new InterpreterController(ps); - controller.run(); + System.out.println("\nProgram has finished."); } } Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-05-08 16:38:23 UTC (rev 106) @@ -9,6 +9,7 @@ import org.binarytranslator.generic.os.abi.linux.LinuxSystemCallGenerator; import org.binarytranslator.generic.os.abi.linux.LinuxSystemCalls; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_Loader; public class ARM_LinuxProcessSpace extends ARM_ProcessSpace { @@ -54,9 +55,12 @@ LinuxStackInitializer.AuxiliaryVectorType.AT_HWCAP, 0x97, LinuxStackInitializer.AuxiliaryVectorType.AT_PAGESZ, 4096, //0x100 LinuxStackInitializer.AuxiliaryVectorType.AT_CLKTCK, 0x17, - LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, 0x8034, - LinuxStackInitializer.AuxiliaryVectorType.AT_PHENT, 0x20, - LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, 0x6, + LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, + ((ELF_Loader)loader).getProgramHeaderAddress(), + LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, + ((ELF_Loader)loader).getNumberOfProgramSegmentHeaders(), + LinuxStackInitializer.AuxiliaryVectorType.AT_PHENT, + ((ELF_Loader)loader).getProgramSegmentHeaderSize(), LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x40000000, LinuxStackInitializer.AuxiliaryVectorType.AT_FLAGS, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, 0x82b4, @@ -64,7 +68,7 @@ LinuxStackInitializer.AuxiliaryVectorType.AT_EUID, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_GID, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_EGID, 0x0, - LinuxStackInitializer.AuxiliaryVectorType.AT_PLATFORM, 0xbffffecd, + LinuxStackInitializer.AuxiliaryVectorType.AT_PLATFORM, 0xbffffecd, LinuxStackInitializer.AuxiliaryVectorType.AT_NULL, 0x0 }; registers.set(ARM_Registers.SP, LinuxStackInitializer.stackInit(memory, STACK_TOP, getEnvironmentVariables(), auxVector)); Modified: src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java 2007-05-08 16:38:23 UTC (rev 106) @@ -102,9 +102,9 @@ LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, ((ELF_Loader)loader).getProgramHeaderAddress(), LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, - ((ELF_Loader)loader).elfHeader.getNumberOfProgramSegmentHeaders(), + ((ELF_Loader)loader).getNumberOfProgramSegmentHeaders(), LinuxStackInitializer.AuxiliaryVectorType.AT_PHENT, - ((ELF_Loader)loader).elfHeader.getProgramSegmentHeaderSize(), + ((ELF_Loader)loader).getProgramSegmentHeaderSize(), //LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_FLAGS, 0x0, Modified: src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java 2007-05-08 16:38:23 UTC (rev 106) @@ -91,7 +91,7 @@ LinuxStackInitializer.AuxiliaryVectorType.AT_PAGESZ, 0x1000, LinuxStackInitializer.AuxiliaryVectorType.AT_CLKTCK, 0x64, LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, ((ELF_Loader)loader).getProgramHeaderAddress(), - LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, ((ELF_Loader)loader).elfHeader.getNumberOfProgramSegmentHeaders(), + LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, ((ELF_Loader)loader).getNumberOfProgramSegmentHeaders(), LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_FLAGS, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, pc, Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-05-08 16:38:23 UTC (rev 106) @@ -14,7 +14,7 @@ Interpreter interpreter = ps.createInstructionInterpreter(); int pc = ps.getCurrentInstructionAddress(); - + while (!ps.finished) { Interpreter.Instruction instruction = interpreter.decode(pc); Modified: src/org/binarytranslator/generic/memory/DebugMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/DebugMemory.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/generic/memory/DebugMemory.java 2007-05-08 16:38:23 UTC (rev 106) @@ -11,6 +11,7 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; +import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.vmInterface.TranslationHelper; import org.jikesrvm.compilers.opt.ir.OPT_Operand; @@ -219,10 +220,12 @@ // Calculate number of pages int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified - if (addr == 0) { + /*if (addr == 0) { addr = findFreePages(num_pages); - } + }*/ + if (DBT_Options.debugMemory) { System.err.println("Mapping file " + file + " offset=" + offset + " addr=0x" + Integer.toHexString(addr) + " len=" + len @@ -236,15 +239,30 @@ // Sub-optimal file.seek(offset); for (int i = 0; i < num_pages; i++) { + + byte page[]; + // Check pages aren't already allocated if ((readableMemory[pte + i] != null) || (writableMemory[pte + i] != null) || (executableMemory[pte + i] != null)) { + + /*page = readableMemory[pte + i]; + + if (page == null) + page = writableMemory[pte + i]; + + if (page == null) + page = executableMemory[pte + i]; + + if (DBT.VerifyAssertions) DBT._assert(page != null);*/ + throw new Error("Memory map of already mapped location addr=0x" + Integer.toHexString(addr) + " len=" + len); } - // Allocate page - byte page[] = new byte[PAGE_SIZE]; + else + page = new byte[PAGE_SIZE]; //Allocate page + if (i == 0) { // first read, start from offset upto a page length file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); } else if (i == (num_pages - 1)) { // last read @@ -252,6 +270,7 @@ } else { file.read(page); } + if (read) { readableMemory[pte + i] = page; } @@ -272,6 +291,8 @@ + Integer.toHexString(addr) + " len=" + len); } + System.out.println("Unexpected page mapping!!!!!!!!!!!!!!!!!!!!"); + byte[] page; if (write) @@ -284,7 +305,7 @@ } if (read) { - readableMemory[pte + 1] = page; + readableMemory[pte + i] = page; } if (exec) { Copied: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java (from rev 83, src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java) =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java (rev 0) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-05-08 16:38:23 UTC (rev 106) @@ -0,0 +1,1510 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.os.loader.elf; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.WeakHashMap; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.memory.Memory; +import org.binarytranslator.generic.memory.MemoryMapException; +import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public class ELF_File { + + /** + * Wrapper class used for reading the ELF file with the required endianness + */ + private BinaryReader reader; + + /** + * Header of ELF file + */ + private Header header; + + /** + * Program segment headers + */ + private SegmentHeader segmentHeaders[]; + + /** + * Debug information + * @param s string of debug information + */ + private static void report(String s) { + if (DBT_Options.debugLoader) { + System.out.print("ELF Loader:"); + System.out.println(s); + } + } + /** + * Reader for byte and multibyte values respecting endianness. + */ + private abstract static class BinaryReader { + + /** File to read from */ + protected RandomAccessFile rFile; + + /** + * Returns a new ELF_BinaryReader for the specified byte order and file. + * + * @param byteOrder + * The byte order that the file posesses. + * @param file + * The file that is to be read. + * @return + * An ELF_BinaryReader, that hides the details of the byte order. + */ + public static BinaryReader create(ELF_Identity.ByteOrder byteOrder, RandomAccessFile file) { + + if (byteOrder == ELF_Identity.ByteOrder.BigEndian) + return new NonSwappingReader(file); + else + return new ByteSwappingReader(file); + } + + /** Hide the constructor, because this class shall only be instantiated by using the factory method {@link #create(org.binarytranslator.generic.os.loader.elf.ELF_Loader.Header.ByteOrder, RandomAccessFile)}. */ + private BinaryReader(RandomAccessFile rFile) { + this.rFile = rFile; + } + + /** Seek to location from beginning of file */ + void seek(long pos) throws IOException { + rFile.seek(pos); + } + + /** Reads a single byte from an ELF file. */ + public byte readByte() throws IOException { + return rFile.readByte(); + } + + /** Read an integer from the file. This function is supposed to hide the difference between little and big endian reads. */ + public abstract int readInt() throws IOException; + + /** Read a short from the file. This function is supposed to hide the difference between little and big endian reads. */ + public abstract short readShort() throws IOException; + + /** Reader that performs byte swaps for each int/short read. */ + private static class ByteSwappingReader extends BinaryReader { + + ByteSwappingReader(RandomAccessFile rFile) { + super(rFile); + } + + /** Byte swap a 32-bit integer */ + private static int bswap(int x) { + return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) + | (x >>> 24); + } + + /** Byte swap a 16-bit integer */ + private static short bswap(short x) { + short result = (short) (((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)); + return result; + } + + @Override + public int readInt() throws IOException { + return bswap(rFile.readInt()); + } + + @Override + public short readShort() throws IOException { + return bswap(rFile.readShort()); + } + } + + /** Reader that does not perform any byte swaps.*/ + private static class NonSwappingReader extends BinaryReader { + + NonSwappingReader(RandomAccessFile rFile) { + super(rFile); + } + + @Override + public int readInt() throws IOException { + return rFile.readInt(); + } + + @Override + public short readShort() throws IOException { + return rFile.readShort(); + } + } + } + + /** + * Returns an Object representation of this ELF's header file. + */ + public Header getHeader() { + return header; + } + + /** Returns an array of program segment headers within this elf.*/ + public SegmentHeader[] getProgramSegmentHeaders() { + return segmentHeaders; + } + + /** Returns the dynamic section, which is identifed by the PT_DYNAMIC segment header. */ + public DynamicSection getDynamicSection() throws IOException { + + for (ELF_File.SegmentHeader segment : segmentHeaders) + if (segment.p_type == ELF_File.SegmentHeader.PT_DYNAMIC) { + return segment.asDynamicSection(); + } + + return null; + } + + /** + * Reads an ELF File from a binary. + * @param filename the program file name + * @return An object representation of the ELF file + */ + public ELF_File(String filename) throws IOException { + report("Opening File: " + filename); + RandomAccessFile rFile = new RandomAccessFile(filename, "r"); + + // Read the ELF Header, which will also provide us with a reader object, that hides ELF endianness + header = new Header(rFile); + reader = header.getReader(); + + report("ELF header read successfully"); + + //read the program segment headers + report("Reading program segment headers"); + segmentHeaders = new SegmentHeader[header.getNumberOfProgramSegmentHeaders()]; + reader.seek(header.getProgramSegmentHeaderOffset()); + + for (int i = 0; i < segmentHeaders.length; i++) { + segmentHeaders[i] = new SegmentHeader(reader); + } + + /* + report("Creating program segments"); + for (int i = 0; i < segmentHeaders.length; i++) { + report("Creating: " + segmentHeaders[i]); + segmentHeaders[i].create(ps); + } + + int brk; + if (segmentHeaders.length > 1) { + brk = segmentHeaders[1].getEnd(); + } else { + brk = segmentHeaders[0].getEnd(); + } + report("Initialising the process space: " + "entry = 0x" + + Integer.toHexString(elfHeader.getEntryPoint()) + " brk = 0x" + + Integer.toHexString(brk)); + ps.initialise(this, elfHeader.getEntryPoint(), brk); + + return ps;*/ + } + + /** + * Determine if the id array corresponds with the initial part of an ELF + * binary + * @param filename Name of the file to check + * @return whether this is an ELF binary + */ + public static boolean conforms(String filename) { + + RandomAccessFile rFile = null; + report("Testing is file is ELF: " + filename); + + try { + rFile = new RandomAccessFile(filename, "r"); + byte[] id = new byte[4]; + rFile.read(id); + + return (id[0] == 0x7f) && (id[1] == 'E') && (id[2] == 'L') + && (id[3] == 'F'); + } catch (Exception e) { + return false; + } finally { + try { + rFile.close(); + } catch (Exception e) { + } + } + } + + /** + * Where did the program header get loaded in memory? + */ + public int getProgramHeaderAddress() { + return segmentHeaders[0].p_vaddr; + //return header.e_phoff - segmentHeaders[0].p_offset + segmentHeaders[0].p_vaddr; + } + + /** An interface for enums where each value is identified by an identifier.*/ + private static interface IdentifiedEnum { + int getIdentifier(); + } + + /** Returns the segment that the given virtual address belongs to. */ + public SegmentHeader virtualAddressToSegment(int virtualAddress) { + + for (int i = 0; i < segmentHeaders.length; i++) { + int offsetWithinSegment = (virtualAddress - segmentHeaders[i].p_vaddr); + + if (offsetWithinSegment > 0 && offsetWithinSegment < segmentHeaders[i].p_memsz) { + return segmentHeaders[i]; + } + } + + return null; + } + + /** + * Creates a corresponding enum value from an integer identifier for enums implementing the {@link IdentifiedEnum} interface. + * In case no corresponding enum value is available, the function returns null. */ + private static <T extends Enum<T> & IdentifiedEnum> T getEnumFromIdentifier(Class<T> enumClass, int identifier) { + for (T value : enumClass.getEnumConstants()) + if (value.getIdentifier() == identifier) + return value; + + return null; + } + + /** + * Class to read and hold ELF header indentity information + */ + @SuppressWarnings("unused") + private static class ELF_Identity { + + private BinaryReader reader; + + /** Represents acceptable ELF address sizes. */ + private enum AddressSize implements IdentifiedEnum { + Size32(1), + Size64(2); + + private int identifier; + + private AddressSize(int identifier) { + this.identifier = identifier; + } + + public int getIdentifier() { + return identifier; + } + } + + /** Represents accepted ELF byte orders. */ + private enum ByteOrder implements IdentifiedEnum { + LittleEndian(1), + BigEndian(2); + + private int identifier; + + private ByteOrder(int identifier) { + this.identifier = identifier; + } + + public int getIdentifier() { + return identifier; + } + } + + /* Symbolic names for the most widely used ABIs. This is not an enum, because the list isn't complete. */ + private static final byte ELFOSABI_SYSTEMV = 0; + private static final byte ELFOSABI_HPUX = 1; + private static final byte ELFOSABI_NETBSD = 2; + private static final byte ELFOSABI_LINUX = 3; + private static final byte ELFOSABI_SOLARIS = 6; + private static final byte ELFOSABI_AIX = 7; + private static final byte ELFOSABI_IRIX = 8; + private static final byte ELFOSABI_FREEBSD = 9; + private static final byte ELFOSABI_TRU64 = 10; + private static final byte ELFOSABI_MODESTO = 11; + private static final byte ELFOSABI_OPENBSD = 12; + private static final byte ELFOSABI_OPENVMS = 13; + private static final byte ELFOSABI_NSK = 14; + private static final byte ELFOSABI_ARM = 97; + + /** + * ELF magic values indicating an ELF file + */ + private static final byte ELF_MAGIC_VALUE[] = { 0x7f, 'E', 'L','F' }; + + /** Specifies the size of an address within this elf.*/ + private AddressSize addressSize; + + /** The byte order used by this elf.*/ + private ByteOrder byteOrder; + + /** The ABI that is used by this ELF.*/ + private byte abi; + + /** + * Construct/read ELF identity + */ + ELF_Identity(RandomAccessFile rFile) throws IOException { + // Identification is in bytes and therefore is endian agnostic + byte[] magic = new byte[ELF_MAGIC_VALUE.length]; + + if (rFile.read(magic) != magic.length) + throw new IOException("ELF file too short."); + + // Check that the ELF magic is correct + for (int i = 0; i < ELF_MAGIC_VALUE.length; i++) { + if (magic[i] != ELF_MAGIC_VALUE[i]) { + throw new IOException("Bad ELF file magic: " + rFile); + } + } + + //read the address size + addressSize = getEnumFromIdentifier(AddressSize.class, rFile.readByte()); + if (addressSize == null) + throw new IOException("Invalid address sizer specified by ELF file."); + + //read the byte order + byteOrder = getEnumFromIdentifier(ByteOrder.class, rFile.readByte()); + if (byteOrder == null) + throw new IOException("Invalid byte order specified by ELF file."); + + //Check the ELF's file version + if (rFile.readByte() != 1) { + throw new IOException("Invalid ELF File version."); + } + + //read a byte describing the target ABI + abi = rFile.readByte(); + + //skip the remaining padding bytes so that we're arriving at a 16 byte alignment. + if (rFile.skipBytes(8) != 8) { + throw new IOException("ELF file is too short."); + } + + reader = BinaryReader.create(byteOrder, rFile); + } + + public Loader.ABI getABI() + { + //read the OS ABI + switch (abi) { + case ELFOSABI_SYSTEMV: + return Loader.ABI.SystemV; + + case ELFOSABI_LINUX: + return Loader.ABI.Linux; + + case ELFOSABI_ARM: + return Loader.ABI.ARM; + + default: + return Loader.ABI.Undefined; + } + } + + protected BinaryReader getReader() { + return reader; + } + } + + /** + * Class to read and hold ELF header information + */ + @SuppressWarnings("unused") + public static class Header extends ELF_Identity { + + /** A list of possible object file types. */ + enum ObjectFileType implements IdentifiedEnum { + Relocatable(1), + Executable(2), + SharedObject(3), + Core(4); + + private int identifier; + + private ObjectFileType(int identifier) { + this.identifier = identifier; + } + + public int getIdentifier() { + return identifier; + } + } + + /** Object file type */ + private ObjectFileType e_type; + + /** + * Start of OS reserved region + */ + private static final short ET_LOOS = (short) 0xfe00; + + /** + * End of OS reserved region + */ + private static final short ET_HIOS = (short) 0xfeff; + + /** + * Start of processor-specific reserved region + */ + private static final short ET_LOPROC = (short) 0xff00; + + /** + * End of processor-specific reserved region + */ + private static final short ET_HIPROC = (short) 0xffff; + + /** + * The required architecture (machine) for the object file + */ + private short e_machine; + + /* Short names for a few known machine types. Not an enum, because this list is not complete. */ + private static final short EM_M32 = 1; + private static final short EM_SPARC = 2; + private static final short EM_386 = 3; + private static final short EM_68K = 4; + private static final short EM_88K = 5; + private static final short EM_860 = 7; + private static final short EM_MIPS = 8; + private static final short EM_PPC = 20; + private static final short EM_ARM = 40; + private static final short EM_ALPHA = 41; + private static final short EM_SPARCV9 = 43; + + /** + * Object file version + */ + private int e_version; + + /** + * Entry point virtual address. The virtual address to which the system + * first transfers control, thus starting the process. + */ + private int e_entry; + + /** + * Program header table file offset + */ + private int e_phoff; + + /** + * Section header table file offset + */ + private final int e_shoff; + + /** + * Processor-specific flags + */ + private final int e_flags; + + /** + * ELF header size in bytes + */ + private final short e_ehsize; + + /** + * Program header table entry size + */ + private final short e_phentsize; + + /** + * Program header table entry count + */ + private final short e_phnum; + + /** + * Section header table entry size + */ + private final short e_shentsize; + + /** + * Section header table entry count + */ + private final short e_shnum; + + /** + * Section header table index + */ + private final short e_shstrndx; + + /** + * Construct/read ELF header + */ + Header(RandomAccessFile file) throws IOException { + super(file); + + BinaryReader reader = getReader(); + + try { + // Read in rest of header + e_type = getEnumFromIdentifier(ObjectFileType.class, reader.readShort()); + + if (e_type == null) { + throw new Error("Invalid Object file type."); + } + + e_machine = reader.readShort(); + e_version = reader.readInt(); + + if (e_version != 1) { + throw new Error("Unexpected ELF File version: " + e_version); + } + + e_entry = reader.readInt(); + e_phoff = reader.readInt(); + e_shoff = reader.readInt(); + e_flags = reader.readInt(); + e_ehsize = reader.readShort(); + e_phentsize = reader.readShort(); + e_phnum = reader.readShort(); + e_shentsize = reader.readShort(); + e_shnum = reader.readShort(); + e_shstrndx = reader.readShort(); + } catch (IOException e) { + throw new Error(e); + } + } + + /** + * What is the offset in the file of the program headers + */ + public int getProgramSegmentHeaderOffset() { + return e_phoff; + } + + /** + * What's the size of a program segment header? + */ + public int getProgramSegmentHeaderSize() { + return e_phentsize; + } + + /** + * How many program segments are in this ELF binary? + */ + public int getNumberOfProgramSegmentHeaders() { + return e_phnum; + } + + /** + * Return the entry point of the binary + */ + public int getEntryPoint() { + return e_entry; + } + + /** Maps the ISA specified within the ELF file to an ISA supported by Pearcolator. */ + public Loader.ISA getISA() { + switch (e_machine) { + case EM_ARM: + return Loader.ISA.ARM; + + case EM_386: + return Loader.ISA.X86; + + case EM_PPC: + return Loader.ISA.PPC; + + default: + return Loader.ISA.Undefined; + } + } + } + + /** Identifies a named segment range. */ + private enum SegmentRange { + /** SUN reserved segments */ + SunReserved(0x6ffffffa, 0x6fffffff, "SUN Reserved Segment"), + + /** OS reserved segment types */ + OperatingSystem(0x60000000, 0x6fffffff, ("Operating System Segment")), + + /** processor reserved segment types */ + Processor(0x70000000, 0x7fffffff, "Processor Segment"), + + /** remaining (unknown) segment types */ + Unknown(0x0, 0xffffffff, "Unknown Segment"); + + private int lowAddress; + private int highAddress; + private String description; + + private SegmentRange(int from, int to, String description) { + + if (DBT.VerifyAssertions) DBT._assert(from < to); + + lowAddress = from; + highAddress = to; + this.description = description; + } + + public static SegmentRange fromInteger(int address) { + for (SegmentRange range : values()) { + if (range.lowAddress >= address && range.highAddress <= address) + return range; + } + + return null; + } + + @Override + public String toString() { + return description; + } + } + + public class StringTable { + + /** Every string that has been resolved is cached in this map to allow faster retrieval for the next time. */ + private WeakHashMap<Integer, String> cachedStrings = new WeakHashMap<Integer, String>(); + + /** A buffer that holds the table's contents*/ + private byte[] buffer; + + public StringTable(int virtualAddress, int size) throws IOException { + + //initialize the buffer + buffer = new byte[size]; + + //find the segment within which the string table resides + SegmentHeader strTableSeg = virtualAddressToSegment(virtualAddress); + + if (strTableSeg == null) + throw new IOException("Unable to locate the segment within which the string table resides."); + + int offsetWithinSegment = virtualAddress - strTableSeg.p_vaddr; + reader.seek(strTableSeg.p_offset + offsetWithinSegment); + + int readBytes = reader.rFile.read(buffer); + + if (readBytes != buffer.length) + throw new IOException("Unable to read string table from file."); + } + + /** Looks a string table entry up by address. */ + public String lookup(int index) { + if (index >= buffer.length) + throw new IndexOutOfBoundsException("Invalid string table index: " + index); + + String result = cachedStrings.get(index); + + if (result != null) + return result; + + int nextIndex = index; + + result = ""; + byte b = (byte)buffer[nextIndex++]; + + while (b != 0) { + result += (char)b; + b = (byte)buffer[nextIndex++]; + } + + //cache the string that we just found + cachedStrings.put(index, result); + + //and return the result + return result; + } + } + + public class SymbolHashTable { + private final SymbolTable symTab; + private final StringTable strTab; + + private final int buckets[]; + private final int chains[]; + + public SymbolHashTable(SymbolTable symTab, StringTable strTab, int virtualAddress) throws IOException { + this.symTab = symTab; + this.strTab = strTab; + + //find the hash table within the file + SegmentHeader segment = virtualAddressToSegment(virtualAddress); + + if (segment == null) + throw new IOException("Unable to locate the segment within which the hash table resides."); + + int offsetWithinSegment = virtualAddress - segment.p_vaddr; + reader.seek(segment.p_offset + offsetWithinSegment); + + //load the hash table from the file + int bucketCount = reader.readInt(); + int chainCount = reader.readInt(); + + buckets = new int[bucketCount]; + chains = new int[chainCount]; + + for (int i = 0; i < bucketCount; i++) + buckets[i] = reader.readInt(); + + for (int i = 0; i < chainCount; i++) + chains[i] = reader.readInt(); + } + + public SymbolTable.Entry lookup(String symbol) throws IOException { + int hash = getElfHash(symbol); + + //what is the index of that symbol in the symbol table? + int symbolIndex = buckets[hash % buckets.length]; + + while (symbolIndex != SymbolTable.STN_UNDEF) { + //get the symbol that we retrieved from the hash table + SymbolTable.Entry entry = symTab.getEntry(symbolIndex); + String curSymbolname = strTab.lookup(entry.nameIdx); + + //is that the symbol we're looking for? + if (curSymbolname.equals(symbol)) + return entry; + + //if not, follow the chain to the next symbol + symbolIndex = chains[symbolIndex]; + } + + //obviously, we couldn't find this symbol + return null; + } + + private int getElfHash(String symbol) { + + int h = 0; + int g = 0; + int nextChar = 0; + + while (nextChar < symbol.length()) { + h = (h << 4) + (byte) symbol.charAt(nextChar++); + + g = h & 0xf0000000; + if (g != 0) + h ^= g >>> 24; + + h &= ~g; + } + + return h; + } + + + } + + public class SymbolTable { + + /** The undefined symbol index. */ + public final static int STN_UNDEF = 0; + + /** Symbol binding values. All other values are processor-dependant. */ + public final static byte STB_LOCAL = 0; + public final static byte STB_GLOBAL = 1; + public final static byte STB_WEAK = 2; + + /** Symbol types. */ + public final static byte STT_NOTYPE = 0; + public final static byte STT_OBJECT = 1; + public final static byte STT_FUNC = 2; + public final static byte STT_SECTION = 3; + public final static byte STT_FILE = 4; + + /** Some section indices have special meanings: */ + public final static short SHN_ABS = (short)0xfff1; + public final static short SHN_COMMON = (short)0xfff2; + public final static short SHN_UNDEF = 0; + + public class Entry { + public final int nameIdx; + public final int value; + public final int size; + public final byte binding; + public final byte type; + public final short sectionIndex; + + public Entry(int nameIdx, int value, int size, byte binding, byte type, short sectionIndex) { + this.nameIdx = nameIdx; + this.value = value; + this.size = size; + this.binding = binding; + this.type = type; + this.sectionIndex = sectionIndex; + } + + final boolean isUndefined() { + return sectionIndex == SHN_UNDEF; + } + } + + /** Every symbol that has been retrieved previously is cached in this map to allow faster access for the next time. */ + private WeakHashMap<Integer, Entry> cachedSymbols = new WeakHashMap<Integer, Entry>(); + + /** Offset at which the symbol table starts within the file. */ + private final int fileOffset; + + /** size of a single entry within the symbol table */ + private final int entrySize; + + public SymbolTable(int virtualAddress, int entrySize) throws IOException { + SegmentHeader segment = virtualAddressToSegment(virtualAddress); + int offset = virtualAddress - segment.p_vaddr; + + fileOffset = segment.p_offset + offset; + this.entrySize = entrySize; + } + + public Entry getEntry(int index) throws IOException { + + //check if we already have cached version of this symbol + Entry result = cachedSymbols.get(index); + + if (result != null) + return result; + + //no, we have to read it from the file + reader.seek(fileOffset + entrySize * index); + + int name = reader.readInt(); + int addr = reader.readInt(); + int size = reader.readInt(); + byte info = reader.readByte(); + reader.readByte(); //skip an empty byte + short sectionIndex = reader.readShort(); + + //create the requested entry... + result = new Entry(name, addr, size, (byte)(info >>> 4), (byte)(info & 0xF), sectionIndex); + + //cache it for the next time + cachedSymbols.put(index, result); + + return result; + } + } + + public class RelocationTable { + + public final ArrayList<Entry> entries; + public final boolean hasAddends; + + public class Entry { + public final int offset; + public final int symbolIndex; + public final byte relocationType; + public final int addend; + + public Entry(int offset, int symbolindex, byte relocationType, int addend) { + this.offset = offset; + this.symbolIndex = symbolindex; + this.relocationType = relocationType; + this.addend = addend; + } + + @Override + public String toString() { + return String.format("Offset: %d, Symbol: %d, Type: %d, Addend: %d", offset, symbolIndex, relocationType, addend); + } + } + + public RelocationTable(int virtualAddress, int tableSize, int entrySize, boolean hasAddends) throws IOException { + + //check the parameters + if (tableSize < 0 || entrySize < 0) { + throw new InvalidParameterException("Cannot create relocation section from invalid section sizes."); + } + + this.entries = new ArrayList<Entry>(); + this.hasAddends = hasAddends; + + //find the segment within which the string table resides + SegmentHeader strTableSeg = virtualAddressToSegment(virtualAddress); + + if (strTableSeg == null) + throw new IOException("Unable to locate the segment within which the relocation section resides."); + + int offsetWithinSegment = virtualAddress - strTableSeg.p_vaddr; + virtualAddress = strTableSeg.p_offset + offsetWithinSegment; + + while (tableSize >= entrySize) { + reader.seek(virtualAddress); + + //read a single relocation entry + int offset = reader.readInt(); + int info = reader.readInt(); + int addend = 0; + + if (hasAddends) + addend = reader.readInt(); + + //add it to the list of relocation entries + entries.add(new Entry(offset, info >>> 8, (byte)(info & 0xFF), addend)); + + //skip to the next entry + virtualAddress += entrySize; + tableSize -= entrySize; + } + } + + @Override + public String toString() { + String result = ""; + + for (int i = 0; i < entries.size(); i++) + result += entries.get(i).toString() + "\n"; + + return result; + } + } + + public class DynamicSection { + public final static int DT_NULL = 0; + public final static int DT_NEEDED = 1; + public final static int DT_PLTRELSZ = 2; + public final static int DT_PLTGOT = 3; + public final static int DT_HASH = 4; + public final static int DT_STRTAB = 5; + public final static int DT_SYMTAB = 6; + public final static int DT_RELA = 7; + public final static int DT_RELASZ = 8; + public final static int DT_RELAENT = 9; + public final static int DT_STRSZ = 10; + public final static int DT_SYMENT = 11; + public final static int DT_INIT = 12; + public final static int DT_FINI = 13; + public final static int DT_SONAME = 14; + public final static int DT_RPATH = 15; + public final static int DT_SYMBOLIC = 16; + public final static int DT_REL = 17; + public final static int DT_RELSZ = 18; + public final static int DT_RELENT = 19; + public final static int DT_PLTREL = 20; + public final static int DT_DEBUG = 21; + public final static int DT_TEXTREL = 22; + public final static int DT_JMPREL = 23; + public final static int DT_BIND_NOW = 24; + + public class Entry { + public final int type; + public final int value; + + private Entry(int type, int value) { + this.type = type; + this.value = value; + } + + @Override + public String toString() { + return String.format("Type: %d, Value: 0x%x", type, value); + } + } + + /** the entries within the dynamic section */ + private ArrayList<Entry> entries = new ArrayList<Entry>(); + + /** the string table referenced by the dynamic section */ + private StringTable strTab; + + /** The symbol table referenced by this dynamic section. */ + private SymbolTable symTab; + + /** The hash table referenced by this dynamic section. */ + private SymbolHashTable hashTab; + + /** The relA section (if present) that is referenced within this dynamic section */ + private RelocationTable relaTab; + + /** The rel section (if present) that is referenced within this dynamic section */ + private RelocationTable relTab; + + public DynamicSection(SegmentHeader segment) throws IOException { + + if (segment.p_type != SegmentHeader.PT_DYNAMIC) + throw new InvalidParameterException("segment is not of type PT_DYNAMIC."); + + reader.seek(segment.p_offset); + Entry entry; + + do { + int type = reader.readInt(); + int value = reader.readInt(); + + entry = new Entry(type, value); + entries.add(entry); + } + while (entry.type != DT_NULL); + } + + public Entry getEntryByType(int type) { + for(Entry entry : entries) + if (entry.type == type) + return entry; + + return null; + } + + public Entry[] getEntriesByType(int type) { + ArrayList<Entry> matches = new ArrayList<Entry>(); + + for(Entry entry : entries) + if (entry.type == type) + matches.add(entry); + + Entry[] result = new Entry[matches.size()]; + return matches.toArray(result); + } + + public SymbolHashTable findHashTable() throws IOException { + if (hashTab != null) + return hashTab; + + Entry tabLocation = getEntryByType(DT_HASH); + + SymbolTable symTab = findSymbolTable(); + StringTable strTab = findStringTable(); + + if (symTab == null || strTab == null || tabLocation == null) + return null; + + hashTab = new SymbolHashTable(symTab, strTab, tabLocation.value); + return hashTab; + } + + public SymbolTable findSymbolTable() throws IOException { + + if (symTab != null) + return symTab; + + Entry tabLocation = getEntryByType(DT_SYMTAB); + Entry entrySize = getEntryByType(DT_SYMENT); + + if (tabLocation == null || entrySize == null) + return null; + + symTab = new SymbolTable(tabLocation.value, entrySize.value); + return symTab; + } + + public StringTable findStringTable() throws IOException { + + if (strTab != null) + return strTab; + + Entry tabLocation = getEntryByType(DT_STRTAB); + Entry tabSize = getEntryByType(DT_STRSZ); + + if (tabLocation == null || tabSize == null) + return null; + + strTab = new StringTable(tabLocation.value, tabSize.value); + return strTab; + } + + public RelocationTable findJmpRelTable() throws IOException { + + Entry tabLocation = getEntryByType(DT_JMPREL); + Entry tabSize = getEntryByType(DT_PLTRELSZ); + Entry entrySize = getEntryByType(DT_RELENT); + Entry entryType = getEntryByType(DT_PLTREL); + + if (tabLocation == null || tabSize == null || entrySize == null | entryType == null) + return null; + + relaTab = new RelocationTable(tabLocation.value, tabSize.value, entrySize.value, entryType.value == DT_RELA); + + return relaTab; + } + + public RelocationTable findRelaTable() throws IOException { + + if (relaTab != null) + return relaTab; + + Entry tabLocation = getEntryByType(DT_RELA); + Entry tabSize = getEntryByType(DT_RELASZ); + Entry entrySize = getEntryByType(DT_RELAENT); + + if (tabLocation == null || tabSize == null || entrySize == null) + return null; + + relaTab = new RelocationTable(tabLocation.value, tabSize.value, entrySize.value, true); + + return relaTab; + } + + public RelocationTable findRelTable() throws IOException { + + if (relTab != null) + return relTab; + + Entry tabLocation = getEntryByType(DT_REL); + Entry tabSize = getEntryByType(DT_RELSZ); + Entry entrySize = getEntryByType(DT_RELENT); + + if (tabLocation == null || tabSize == null || entrySize == null) + return null; + + relTab = new RelocationTable(tabLocation.value, tabSize.value, entrySize.value, false); + return relTab; + } + + @Override + public String toString() { + String result = ""; + + for(Entry entry : entries) + result = result + entry.toString() + "\n"; + + return result; + } + } + + /** + * Header representing a segment in the process (e.g. stack, heap, code aka + * text) in the ELF file. These are known as program header's in the ELF + * literature, but they don't represent programs, rather separate segments. + */ + @SuppressWarnings("unused") + public class SegmentHeader { + /** + * Type of the segment + */ + public final int p_type; + + /** + * Null header, contains no data and can be ignored + */ + public static final int PT_NULL = 0; + + /** + * A loadable segment + */ + public static final int PT_LOAD = 1; + + /** + * Segment containing dynamic linking information + */ + public static final int PT_DYNAMIC = 2; + + /** + * A segment containing a string to invoke as interpreter for this file + */ + public static final int PT_INTERP = 3; + + /** + * A segment describing the location and size of auxiliary information + */ + public static final int PT_NOTE = 4; + + /** + * A reserved segment type with unspecified semantics + */ + public static final int PT_SHLIB = 5; + + /** + * A segment describing the ELF's header, present once before any loadable + * segments + */ + public static final int PT_PHDR = 6; + + /** + * Thread local storage (TLS) segment + */ + public static final int PT_TLS = 7; + + + /** + * Start of OS reserved segment types + */ + + /** + * SUN unwind table segment + */ + public static final int PT_SUNW_UNWIND = 0x6464e550; + + /** + * GCC .eh_frame_hdr segment + */ + public static final int PT_GNU_EH_FRAME = 0x6474e550; + + /** + * Indicates stack executability + */ + public static final int PT_GNU_STACK = 0x6474e551; + + /** + * Read-only after relocation + */ + public static final int PT_GNU_RELRO = 0x6474e552; + + /** + * Start of SUN reserved segments + */ + + /** + * The array element has the same attributes as a PT_LOAD element and is + * used to describe a .SUNW_bss section. + */ + public static final int PT_SUNWBSS = 0x6ffffffa; + + /** + * Describes a process stack. Only one PT_SUNWSTACK element can exist. Only + * access permissions, as defined in the p_flags field, are meaningful. + */ + public static final int PT_SUNWSTACK = 0x6ffffffb; + + /** + * Reserved for internal use by dtrace + */ + public static final int PT_SUNWDTRACE = 0x6ffffffc; + + /** + * Specifies hardware capability requirements + */ + public static final int PT_SUNWCAP = 0x6ffffffd; + + /** + * End of SUN reserved segments + */ + + /** + * End of OS reserved segment types + */ + + + /** + * Offset of first byte of segment data in file + */ + public final int p_offset; + + /** + * Virtual address of first byte in segment + */ + public final int p_vaddr; + + /** + * Corresponding physical addressed used by some systems + */ + public int p_paddr; + + /** + * Size of segment in file + */ + public final int p_filesz; + + /** + * Size of segment in memory + */ + public final int p_memsz; + + /** + * Read/Write/Execute flags for segment in memory + */ + public int p_flags; + + /** + * Executable flag + */ + public static final int PF_X = 0x1; + + /** + * Writable flag + */ + public static final int PF_W = 0x2; + + /** + * Readable flag + */ + public static final int PF_R = 0x4; + + /** + * OS specific reserved bits + */ + private static final int PF_MASKOS = 0x0ff00000; + + /** + * Processor specific reserved bits + */ + private static final int PF_MASKPROC = 0xf0000000; + + /** + * This member gives the value to which the segments are aligned in memory + * and in the file. Values 0 and 1 mean no alignment is required. Otherwise, + * p_align should be a positive, integral power of 2, and p_vaddr should + * equal p_offset, modulo p_align. + */ + private final int p_align; + + /** + * Construct a program segment header reading in from the reader + */ + private SegmentHeader(BinaryReader reader) throws IOException { + p_type = reader.readInt(); + p_offset = reader.readInt(); + p_vaddr = reader.readInt(); + p_paddr = reader.readInt(); + p_filesz = reader.readInt(); + p_memsz = reader.readInt(); + p_flags = reader.readInt(); + p_align = reader.readInt(); + // Move file onto next program segment header offset + reader.rFile.skipBytes(header.getProgramSegmentHeaderSize() - 32); + } + + public DynamicSection asDynamicSection() throws IOException { + return new DynamicSection(this); + } + + void create(ProcessSpace ps) { + create(ps, 0); + } + + /** + * Load/create the program segment + */ + void create(ProcessSpace ps, int offset) { + switch (p_type) { + case PT_NULL: // Null header, contains no data and can be ignored + break; + + case PT_LOAD: // A loadable segment + try { + createSegment(ps.memory, reader.rFile, p_offset, p_vaddr + offset, p_filesz, + p_memsz, (p_flags & PF_R) != 0, (p_flags & PF_W) != 0, + (p_flags & PF_X) != 0); + } catch (MemoryMapException e) { + throw new Error("Error in creating: " + this, e); + } + break; + case PT_PHDR: + case PT_NOTE: // A segment describing the location and size of auxiliary + // information + // ignore + break; + case PT_GNU_STACK: // A segment describing the permissions for the stack + // ignore + break; + case PT_TLS: // A segment describing thread local storage + // ignore for now + break; + case PT_INTERP: // A segment containing a string to invoke as interpreter + // for this file + case PT_DYNAMIC: // Segment containing dynamic linking information + case PT_SHLIB: // A reserved segment type with unspecified semantics + //case PT_PHDR: // A segment describing the ELF's header; present once + // before any loadable segments + default: + return; + //throw new Error("Segment type " + toString() + " not yet supported"); + } + } + + /** + * Create a segment + * @param memory The memory into which the segment is to be mapped. + * @param file file to read segment data from if file size != 0 + * @param offset file offset + * @param address location of segment + * @param filesize size of segment in file + * @param memsize size of segment in memory + * @param read is segment readable + * @param write is segment writable + * @param exec is segment executable + */ + public void createSegment(Memory memory, RandomAccessFile file, + long offset, int address, int filesize, int memsize, boolean read, + boolean write, boolean exec) throws MemoryMapException { + // Sanity check + if (memsize < filesize) { + throw new Error("Segment memory size (" + memsize + + ")less than file size (" + filesize + ")"); + } + // Are we mapping anything from a file? + if (filesize == 0) { + // No: map anonymously + memory.map(address, memsize, read, write, exec); + } else { + // align offset and address + int alignedAddress; + long alignedOffset; + int alignedFilesize; + if (memory.isPageAligned(address)) { + // memory and therefore offset should be aligned + alignedAddress = address; + alignedOffset = offset; + alignedFilesize = filesize; + } else { + // Address not aligned + alignedAddress = memory.truncateToPage(address); + int delta = address - alignedAddress; + // adjust offset and length too + alignedOffset = offset - delta; + alignedFilesize = filesize + delta; + } + memory.map(file, alignedOffset, alignedAddress, alignedFilesize, read, + write, exec); + // Do we need to map in some blank pages at the end of the segment? + if (filesize < memsize) { + alignedAddress = memory.truncateToNextPage(address + filesize); + memory.map(alignedAddress, memsize - filesize, read, write, exec); + } + } + } + + /** + * Round the give value up so that it is at the beginning of the next + * aligned region + */ + private int truncateToNextAlignment(int x) { + return ((x + p_align - 1) / p_align) * p_align; + } + + /** + * Get the end of the segment + */ + public int getEnd() { + return truncateToNextAlignment(p_vaddr + p_memsz); + } + + /** + * String representation of header + */ + public String toString() { + switch (p_type) { + case PT_NULL: + return "Null segment header (ignored)"; + case PT_LOAD: + return "Loadable segment (offset=0x" + Long.toHexString(p_offset) + + ", address=0x" + Integer.toHexString(p_vaddr) + ", file size=" + + p_filesz + ", memory size=" + p_memsz + ", permissions=" + + (((p_flags & PF_R) != 0) ? 'r' : '-') + + (((p_flags & PF_W) != 0) ? 'w' : '-') + + (((p_flags & PF_X) != 0) ? 'x' : '-') + ")"; + case PT_TLS: + return "TLS segment (offset=0x" + Long.toHexString(p_offset) + + ", address=0x" + Integer.toHexString(p_vaddr) + ", file size=" + + p_filesz + ", memory size=" + p_memsz + ", permissions=" + + (((p_flags & PF_R) != 0) ? 'r' : '-') + + (((p_flags & PF_W) != 0) ? 'w' : '-') + + (((p_flags & PF_X) != 0) ? 'x' : '-') + ")"; + case PT_NOTE: + return "Note: segment containing auxiliary information"; + case PT_INTERP: + return "Interpreter"; + case PT_DYNAMIC: + return "Dynamic link information"; + case PT_SHLIB: + return "SHLIB/Unspecified - semantics unknown"; + case PT_PHDR: + return "Program header"; + case PT_GNU_STACK: + return "GNU stack executability"; + default: + SegmentRange range = SegmentRange.fromInteger(p_type); + return range.toString() + "(0x" + Integer.toHexString(p_type) + ")"; + } + } + } +} Deleted: src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-05-08 16:35:56 UTC (rev 105) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-05-08 16:38:23 UTC (rev 106) @@ -1,968 +0,0 @@ -/* - * This file is part of binarytranslator.org. The binarytranslator.org - * project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 - */ -package org.binarytranslator.generic.os.loader.elf; - -import java.io.IOException; -import java.io.RandomAccessFile; - -import org.binarytranslator.DBT; -import org.binarytranslator.DBT_Options; -import org.binarytranslator.generic.memory.Memory; -import org.binarytranslator.generic.memory.MemoryMapException; -import org.binarytranslator.generic.os.loader.Loader; -import org.binarytranslator.generic.os.process.ProcessSpace; - -public class ELF_Loader extends Loader { - - /** - * Wrapper class used for reading the ELF file with the required endianness - */ - private ELF_BinaryReader reader; - - /** - * Field holding identity information - */ - private ELF_Identity identity; - - /** - * Header of ELF file - */ - public ELF_Header elfHeader; - - /** - * Program segment headers - */ - private ELF_ProgramSegmentHeader segmentHeaders[]; - - /** - * Debug information - * @param s string of debug information - */ - private static void report(String s) { - if (DBT_Options.debugLoader) { - System.out.print("ELF Loader:"); - System.out.println(s); - } - } - /** - * Reader for byte and multibyte values respecting endianness. - */ - private abstract static class ELF_BinaryReader { - - /** File to read from */ - protected RandomAccessFile rFile; - - /** - * Returns a new ELF_BinaryReader for the specified byte order and file. - * - * @param byteOrder - * The byte order that the file posesses. - * @param file - * The file that is to be read. - * @return - * An ELF_BinaryReader, that hides the details of the byte order. - */ - public static ELF_BinaryReader create(ELF_Identity.ByteOrder byteOrder, RandomAccessFile file) { - - if (byteOrder == ELF_Identity.ByteOrder.BigEndian) - return new NonSwappingReader(file); - else - return new ByteSwappingReader(file); - } - - /** Hide the constructor, because this class shall only be instantiated by using the factory method {@link #create(org.binarytranslator.generic.os.loader.elf.ELF_Loader.ELF_Header.ByteOrder, RandomAccessFile)}. */ - private ELF_BinaryReader(RandomAccessFile rFile) { - this.rFile = rFile; - } - - /** Seek to location from beginning of file */ - void seek(long pos) throws IOException { - rFile.seek(pos); - } - - /** Read an integer from the file. This function is supposed to hide the difference between little and big endian reads. */ - public abstract int readInt() throws IOException; - - /** Read a short from the file. This function is supposed to hide the difference between little and big endian reads. */ - public abstract short readShort() throws IOException; - - /** Reader that performs byte swaps for each int/short read. */ - private static class ByteSwappingReader extends ELF_BinaryReader { - - ByteSwappingReader(RandomAccessFile rFile) { - super(rFile); - } - - /** Byte swap a 32-bit integer */ - private static int b... [truncated message content] |
From: <mic...@us...> - 2007-05-10 15:21:58
|
Revision: 111 http://svn.sourceforge.net/pearcolator/?rev=111&view=rev Author: michael_baer Date: 2007-05-10 08:21:58 -0700 (Thu, 10 May 2007) Log Message: ----------- - fixed various problems in ARM's DBT part - fixed an interpreter bug, where LSL and ROR by 32 would produce a wrong result Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/generic/decoder/DecoderUtils.java src/org/binarytranslator/generic/memory/AutoMappingMemory.java src/org/binarytranslator/generic/memory/DebugMemory.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-10 15:21:58 UTC (rev 111) @@ -20,10 +20,22 @@ public class ARM2IR extends DecoderUtils implements OPT_HIRGenerator { /** Mapping of ARM registers to HIR registers */ - protected OPT_Register regMap[] = new OPT_Register[16]; + private OPT_Register regMap[] = new OPT_Register[16]; + /** The ARM carry flag. */ + private OPT_Register carryFlag; + + /** The ARM zero flag. */ + private OPT_Register zeroFlag; + + /** The ARM negative flag. */ + private OPT_Register negativeFlag; + + /** The ARM overflow flag. */ + private OPT_Register overflowFlag; + /** Set to true for each register that is in use during the current trace */ - protected boolean regUsed[] = new boolean[16]; + private boolean regUsed[] = new boolean[16]; /** Type reference to the ARM process space */ private static final VM_TypeReference psTref; @@ -38,15 +50,29 @@ private static final VM_FieldReference registers_regs_Fref; /** A type reference to the ARM registers array within the ARM_Registers class */ - private static final VM_TypeReference registers_regs_Tref; + private static final VM_TypeReference registers_regs_Tref; + /** A field reference to the carry flag within the ARM registers. */ + private static final VM_FieldReference registers_carryFlag_Fref; + + /** A field reference to the zero flag within the ARM registers. */ + private static final VM_FieldReference registers_zeroFlag_Fref; + + /** A field reference to the negative flag within the ARM registers. */ + private static final VM_FieldReference registers_negativeFlag_Fref; + + /** A field reference to the overflow flag within the ARM registers. */ + private static final VM_FieldReference registers_overflowFlag_Fref; + /** A register holding a reference to ps.registers */ private OPT_Register ps_registers; /** A register holding a reference to ps.registers.regs */ private OPT_Register ps_registers_regs; - + /** The class performing the actual translation of the bytecode. */ + private final ARM_Translator translator; + static { psTref = VM_TypeReference.findOrCreate(ARM_ProcessSpace.class); @@ -73,11 +99,40 @@ registers_regs_Tref = registers_regs_Fref.getFieldContentsType(); if (DBT.VerifyAssertions) DBT._assert(registers_regs_Tref != null); + + registers_carryFlag_Fref = VM_MemberReference + .findOrCreate(registersTref, + VM_Atom.findOrCreateAsciiAtom("flagCarry"), + VM_Atom.findOrCreateAsciiAtom("Z")).asFieldReference(); + + if (DBT.VerifyAssertions) DBT._assert(registers_carryFlag_Fref != null); + + registers_zeroFlag_Fref = VM_MemberReference + .findOrCreate(registersTref, + VM_Atom.findOrCreateAsciiAtom("flagZero"), + VM_Atom.findOrCreateAsciiAtom("Z")).asFieldReference(); + + if (DBT.VerifyAssertions) DBT._assert(registers_zeroFlag_Fref != null); + + registers_negativeFlag_Fref = VM_MemberReference + .findOrCreate(registersTref, + VM_Atom.findOrCreateAsciiAtom("flagNegative"), + VM_Atom.findOrCreateAsciiAtom("Z")).asFieldReference(); + + if (DBT.VerifyAssertions) DBT._assert(registers_negativeFlag_Fref != null); + + registers_overflowFlag_Fref = VM_MemberReference + .findOrCreate(registersTref, + VM_Atom.findOrCreateAsciiAtom("flagOverflow"), + VM_Atom.findOrCreateAsciiAtom("Z")).asFieldReference(); + + if (DBT.VerifyAssertions) DBT._assert(registers_overflowFlag_Fref != null); } public ARM2IR(OPT_GenerationContext context) { super(context); + translator = new ARM_Translator((ARM_ProcessSpace)ps, this); } @Override @@ -132,7 +187,7 @@ public OPT_RegisterOperand getArmRegistersReference() { OPT_RegisterOperand ps_registersOp; - if (ps_registers != null) { + if (ps_registers == null) { ps_registersOp = gc.temps.makeTemp(registersTref); ps_registers = ps_registersOp.register; appendInstructionToCurrentBlock(GetField.create(GETFIELD, ps_registersOp, @@ -154,14 +209,49 @@ //first resolve the current lazy state (i.e. calculate the values of registers that are not yet resolved) resolveLaziness(lazyState); + } + + private void spillAllFlags() { + + OPT_RegisterOperand ps_registersOp = getArmRegistersReference(); - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + //store the carry flag + OPT_RegisterOperand flag = new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); + + //store the negative flag + flag = new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); + + //store the zero flag + flag = new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); + + //store the overflow flag + flag = new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); } public void fillAllFlags() { - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + + //get an operand that contains a reference to the current ps.registers field. + OPT_RegisterOperand ps_registersOp = getArmRegistersReference(); + + //get the carry flag + OPT_RegisterOperand flag = new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); + + //get the negative flag + flag = new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); + + //get the zero flag + flag = new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); + + //get the overflow flag + flag = new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); } @Override @@ -199,6 +289,9 @@ new OPT_LocationOperand(VM_TypeReference.Int), new OPT_TrueGuardOperand())); } + + //fill all flags from the process space + fillAllFlags(); } public OPT_RegisterOperand getRegister(int r) { @@ -207,26 +300,21 @@ } public OPT_RegisterOperand getCarryFlag() { - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); } public OPT_RegisterOperand getZeroFlag() { - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); } public OPT_RegisterOperand getNegativeFlag() { - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); } public OPT_RegisterOperand getOverflowFlag() { - //TODO: Implement - throw new RuntimeException("Not yet implemented"); + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); } - @Override protected OPT_Register[] getUnusedRegisters() { @@ -268,13 +356,17 @@ new OPT_TrueGuardOperand())); } } + + //spill all flags to the process space + spillAllFlags(); } @Override protected int translateInstruction(Laziness lazy, int pc) { - return 0xEBADC0DE; - //ARM_InstructionDecoder.translateInstruction(this, - // (ARM_ProcessSpace) ps, (ARM_Laziness) lazy, pc); + System.out.println("Translating address: 0x" + Integer.toHexString(pc)); + System.out.println("Instruction: " + ARM_Disassembler.disassemble(pc, ps)); + + return translator.translateInstruction(pc, (ARM_Laziness)lazy); } /** Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-05-10 15:21:58 UTC (rev 111) @@ -272,7 +272,7 @@ } if (shiftAmount == 32) { - shifterCarryOut = Utils.getBit(value, 31); + shifterCarryOut = (value & 0x1) != 0; return 0; } @@ -311,7 +311,7 @@ return value; } else { - shifterCarryOut = Utils.getBit(value, shiftAmount & 0x1F); + shifterCarryOut = Utils.getBit(value, (shiftAmount-1) & 0x1F); return Integer.rotateRight(value, shiftAmount); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-10 15:21:58 UTC (rev 111) @@ -30,12 +30,29 @@ /** A "quick" pointer to the ARM registers within the process space*/ protected final ARM_Registers regs = null; + + private final ARM_InstructionDecoder.ARM_InstructionFactory<ARM_Instruction> translatorFactory = new TranslatorFactory(); public ARM_Translator(ARM_ProcessSpace ps, ARM2IR arm2ir) { this.ps = ps; this.arm2ir = arm2ir; } + public int translateInstruction(int pc, ARM_Laziness lazy) { + this.pc = pc; + this.lazy = lazy; + + int instruction = ps.memory.loadInstruction32(pc); + ARM_Instruction instr = ARM_InstructionDecoder.decode(instruction, translatorFactory); + + if (instr.getCondition() != Condition.AL) { + instr = new ConditionalDecorator(instr); + } + + instr.translate(); + return instr.getSuccessor(pc); + } + private OPT_Instruction createCallToRegisters(String methodName, String signature, int numParameters) { VM_TypeReference RegistersType = VM_TypeReference @@ -69,9 +86,11 @@ protected ARM_Translator translator; - public static ResolvedOperand resolveAndStoreShifterCarryOutToCarry( + public static OPT_Operand resolveAndStoreShifterCarryOutToCarry( ARM_Translator translator, OperandWrapper operand) { - throw new RuntimeException("Not yet implemented"); + + ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(translator, operand); + return result.getValue(); } public static OPT_Operand resolve(ARM_Translator translator, @@ -167,96 +186,36 @@ .getShiftingRegister()); } - OPT_BasicBlock currentBlock = translator.arm2ir.getCurrentBlock(); - OPT_BasicBlock nextBlock = translator.arm2ir.getNextBlock(); - - OPT_BasicBlock ifBlock; - OPT_BasicBlock elseBlock; - OPT_RegisterOperand resultRegister = getTempInt(); switch (operand.getShiftType()) { case ASR: /* - * if (shiftAmout >= 32) { value = shiftedOperand >> 31; shiftedOperand >> 1; } - * else - * value = shiftedOperand >> shiftAmount; + * shiftedOperand >> shiftAmount; */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - ifBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); - - //shift - translator.arm2ir.setCurrentBlock(ifBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( - INT_SHR, resultRegister, shiftedOperand, - new OPT_IntConstantOperand(31))); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( - INT_SHR, resultRegister, shiftedOperand, - new OPT_IntConstantOperand(1))); - - translator.arm2ir.setCurrentBlock(elseBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_SHR, resultRegister, shiftedOperand, shiftAmount)); - break; + return resultRegister; case LSL: /* - * if (shiftAmout >= 32) { value = 0; else value = shiftedOperand << - * shiftAmount; + * value = shiftedOperand << shiftAmount; */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - ifBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); - - translator.arm2ir.setCurrentBlock(ifBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( - INT_MOVE, resultRegister, new OPT_IntConstantOperand(0))); - - translator.arm2ir.setCurrentBlock(elseBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + return resultRegister; - break; - case LSR: /* - * if (shiftAmout >= 32) { value = 0; else value = shiftedOperand >>> - * shiftAmount; + * value = shiftedOperand >>> shiftAmount; + */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - ifBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); - - translator.arm2ir.setCurrentBlock(ifBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( - INT_MOVE, resultRegister, new OPT_IntConstantOperand(0))); - - translator.arm2ir.setCurrentBlock(elseBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_USHR, resultRegister, shiftedOperand, shiftAmount)); - break; + return resultRegister; case ROR: /* @@ -267,8 +226,8 @@ case RRX: /* - * if (regs.isCarrySet()) return (resultRegister >> 1) | 0x80000000; - * else return resultRegister >>> 1; + * value = resultRegister >>> 1; + * if (regs.isCarrySet()) value |= 0x80000000; */ // resultRegister = resultRegister >>> 1 @@ -276,28 +235,34 @@ INT_USHR_ACC, resultRegister, new OPT_IntConstantOperand(1))); //conditionally, set resultRegister = resultRegister | 0x80000000; - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - ifBlock.insertOut(nextBlock); + OPT_BasicBlock curBlock = translator.arm2ir.getCurrentBlock(); + + OPT_BasicBlock nextBlock = translator.arm2ir.getNextBlock(); + OPT_BasicBlock block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //Current block + curBlock.insertOut(block1); translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( INT_IFCMP, getTempValidation(), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand - .EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); + .EQUAL(), block1.makeJumpTarget(), + new OPT_BranchProfileOperand())); + + //Block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(nextBlock); - translator.arm2ir.setCurrentBlock(ifBlock); translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( INT_OR_ACC, resultRegister, new OPT_IntConstantOperand(0x80000000))); + + translator.arm2ir.setCurrentBlock(nextBlock); + translator.arm2ir.setNextBlock(translator.arm2ir.createBlockAfterCurrent()); + return resultRegister; - break; - default: throw new RuntimeException("Unexpected shift type: " + operand.getShiftType()); } - - translator.arm2ir.setCurrentBlock(nextBlock); - return resultRegister; } } @@ -356,21 +321,9 @@ } } - /** - * Translates a bit test, where bit <code>shifterResultBit</code> is tested within <code>value</code> and the result - * is put into the carry flag If <code>shifterResultBit</code> is less than 0, the carry is not changed. - * - */ - private void translateShifterCarryOut(OPT_Operand value, OPT_Operand shifterResultBit) { - - OPT_RegisterOperand carryFlag = translator.arm2ir.getCarryFlag(); - - - OPT_RegisterOperand tmp = getTempInt(); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, - tmp, shifterResultBit, new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( - BOOLEAN_CMP_INT, carryFlag, value, tmp.copyRO(), OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand())); + /** Returns the register that receives the shifte carry out*/ + private OPT_RegisterOperand getShifterCarryOutTarget() { + return translator.arm2ir.getCarryFlag(); } /** @@ -402,140 +355,185 @@ .getShiftingRegister()); } - OPT_BasicBlock currentBlock = translator.arm2ir.getCurrentBlock(); + OPT_RegisterOperand resultRegister = getTempInt(); + OPT_BasicBlock nextBlock = translator.arm2ir.getNextBlock(); + OPT_BasicBlock curBlock = translator.arm2ir.getCurrentBlock(); + OPT_BasicBlock block1, block2, block3; + + OPT_RegisterOperand validation1 = translator.arm2ir.getTempValidation(9); + OPT_RegisterOperand validation2 = translator.arm2ir.getTempValidation(8); + + OPT_RegisterOperand tmp = translator.arm2ir.getTempInt(9); - OPT_BasicBlock ifBlock; - OPT_BasicBlock elseBlock; - - OPT_RegisterOperand resultRegister = getTempInt(); - switch (operand.getShiftType()) { case ASR: /* - * if (shiftAmout >= 32) { value = shiftedOperand >> 31; shiftedOperand >> 1; } - * else - * value = shiftedOperand >> shiftAmount; + * shiftedOperand >> shiftAmount; + * + * if (shiftAmount != 0) { + * shiftAmount = MIN(shiftAmount, 32); + * carry = shiftedOperand[shiftAmount] + * } */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - ifBlock.insertOut(nextBlock); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - new OPT_BranchProfileOperand())); - currentBlock.insertOut(ifBlock); - - //shift twice to simulate arithmetic shift-right by 32 - //circumvents java doing (shiftAmount MOD 32). - translator.arm2ir.setCurrentBlock(ifBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( - INT_SHR, resultRegister, shiftedOperand, - new OPT_IntConstantOperand(31))); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( - INT_SHR, resultRegister, shiftedOperand, - new OPT_IntConstantOperand(1))); - - translator.arm2ir.setCurrentBlock(elseBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_SHR, resultRegister, shiftedOperand, shiftAmount)); - translateShifterCarryOut(resultRegister, shiftAmount); + + block3 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block2 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //current block + curBlock.insertOut(block1); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation1, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), nextBlock.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(block2); + block1.insertOut(block3); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation2, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 2 + translator.arm2ir.setCurrentBlock(block2); + block2.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, shiftAmount, OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); + + //block 3 + translator.arm2ir.setCurrentBlock(block3); + block3.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, new OPT_IntConstantOperand(32), OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); + break; case LSL: /* - * if (shiftAmout >= 32) { value = 0; else value = shiftedOperand << - * shiftAmount; + * value = shiftedOperand << shiftAmount; */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - ifBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); - - translator.arm2ir.setCurrentBlock(ifBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( - INT_MOVE, resultRegister, new OPT_IntConstantOperand(0))); - - translator.arm2ir.setCurrentBlock(elseBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + + block3 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block2 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //current block + curBlock.insertOut(block1); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation1, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), nextBlock.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(block2); + block1.insertOut(block3); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation2, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 2 + translator.arm2ir.setCurrentBlock(block2); + block2.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock( Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, tmp, OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); + + //block 3 + translator.arm2ir.setCurrentBlock(block3); + block3.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock( Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); break; case LSR: /* - * if (shiftAmout >= 32) { value = 0; else value = shiftedOperand >>> - * shiftAmount; + * value = shiftedOperand >>> shiftAmount; + */ - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - elseBlock = translator.arm2ir.createBlockAfterCurrent(); - ifBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( - INT_IFCMP, getTempValidation(), shiftAmount, - new OPT_IntConstantOperand(32), OPT_ConditionOperand - .GREATER_EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); - - translator.arm2ir.setCurrentBlock(ifBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( - INT_MOVE, resultRegister, new OPT_IntConstantOperand(0))); - - translator.arm2ir.setCurrentBlock(elseBlock); translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( INT_USHR, resultRegister, shiftedOperand, shiftAmount)); + block3 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block2 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //current block + curBlock.insertOut(block1); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation1, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), nextBlock.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(block2); + block1.insertOut(block3); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation2, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 2 + translator.arm2ir.setCurrentBlock(block2); + block2.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, shiftAmount, OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); + + //block 3 + translator.arm2ir.setCurrentBlock(block3); + block3.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock( Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); + break; case ROR: /* * return Integer.rotateRight(value, shiftAmount); */ - translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand, - shiftAmount); - return resultRegister; + translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand, shiftAmount); + + block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //current block + curBlock.insertOut(block1); + translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation1, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), nextBlock.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + + //block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(nextBlock); + translator.arm2ir.appendInstructionToCurrentBlock( Binary.create(INT_SUB, tmp, shiftAmount, new OPT_IntConstantOperand(1)) ); + translator.arm2ir.appendInstructionToCurrentBlock( Binary.create(INT_AND, tmp, shiftAmount, new OPT_IntConstantOperand(0x1F)) ); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, tmp, OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); + + break; case RRX: /* - * if (regs.isCarrySet()) return (resultRegister >> 1) | 0x80000000; - * else return resultRegister >>> 1; + * value = resultRegister >>> 1; + * if (regs.isCarrySet()) value |= 0x80000000; */ // resultRegister = resultRegister >>> 1 translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( INT_USHR_ACC, resultRegister, new OPT_IntConstantOperand(1))); + translator.arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create(BOOLEAN_CMP_INT, getShifterCarryOutTarget(), shiftedOperand, new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), new OPT_BranchProfileOperand()) ); - ifBlock = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - ifBlock.insertOut(nextBlock); + //conditionally, set resultRegister = resultRegister | 0x80000000; + block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); + + //Current block + curBlock.insertOut(block1); translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create( INT_IFCMP, getTempValidation(), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand - .EQUAL(), ifBlock.makeJumpTarget(), - OPT_BranchProfileOperand.unlikely())); - currentBlock.insertOut(ifBlock); + .EQUAL(), block1.makeJumpTarget(), + new OPT_BranchProfileOperand())); + + //Block 1 + translator.arm2ir.setCurrentBlock(block1); + block1.insertOut(nextBlock); - translator.arm2ir.setCurrentBlock(ifBlock); translator.arm2ir.appendInstructionToCurrentBlock(Unary.create( - INT_AND_ACC, resultRegister, new OPT_IntConstantOperand( - 0x80000000))); - + INT_OR_ACC, resultRegister, new OPT_IntConstantOperand(0x80000000))); + break; default: throw new RuntimeException("Unexpected shift type: " + operand.getShiftType()); } - + translator.arm2ir.setCurrentBlock(nextBlock); + translator.arm2ir.setNextBlock( translator.arm2ir.createBlockAfterCurrent() ); return resultRegister; } } @@ -564,6 +562,9 @@ /** performs the actual translation.*/ void translate(); + + /** Return the instruction following this one or -1, if that is not yet known. */ + int getSuccessor(int pc); } /** All ARM instructions that are supposed to be executed conditionally @@ -579,6 +580,14 @@ conditionalInstruction = i; } + public int getSuccessor(int pc) { + //if this instruction is not a jump, then we can tell what the next instruction will be. + if (conditionalInstruction.getSuccessor(pc) == pc + 4) + return pc + 4; + else + return -1; + } + public void translate() { //conditionals are implemented easily: if the condition does not hold, then just //jump to the block following the conditional instruction @@ -880,8 +889,7 @@ protected OPT_Operand resolveOperand2() { if (updateConditionCodes) { - ResolvedOperand resolvedOperand2 = ResolvedOperand.resolveAndStoreShifterCarryOutToCarry(ARM_Translator.this, operand2); - return resolvedOperand2.getValue(); + return ResolvedOperand.resolveAndStoreShifterCarryOutToCarry(ARM_Translator.this, operand2); } else { return super.resolveOperand2(); @@ -2032,9 +2040,9 @@ } - /** This class will create instances of the different interpreter instructions. It is being "controlled" by + /** This class will create instances of the different translated instructions. It is being "controlled" by * the ARM_InstructionDecoder, which uses an abstract factory pattern to decode an instruction. */ - private class InterpreterFactory implements + private class TranslatorFactory implements ARM_InstructionFactory<ARM_Instruction> { public ARM_Instruction createDataProcessing(int instr) { Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-05-10 15:21:58 UTC (rev 111) @@ -2,6 +2,7 @@ import java.io.IOException; import org.binarytranslator.DBT_Options; +import org.binarytranslator.arch.arm.decoder.ARM2IR; import org.binarytranslator.arch.arm.decoder.ARM_Interpreter; import org.binarytranslator.arch.arm.os.process.image.ARM_ImageProcessSpace; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; @@ -47,8 +48,7 @@ * @return a HIR generator */ public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { - System.out.println("Executing instr: " + memory.load32(0)); - throw new RuntimeException("Not yet implemented"); + return new ARM2IR(context); } /** Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-05-10 15:21:58 UTC (rev 111) @@ -9,8 +9,6 @@ import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.memory.AutoMappingMemory; import org.binarytranslator.generic.os.loader.Loader; -import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; -import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { @@ -22,12 +20,6 @@ //make sure that pages of memory are automatically mapped in as they are requested. memory = new AutoMappingMemory(memory); } - - @Override - public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) - { - throw new UnsupportedOperationException("Not yet implemented."); - } @Override public void doSysCall() { @@ -37,9 +29,7 @@ ARM_Instructions.Instruction instr = ARM_InstructionDecoder.decode(instruction); if (DBT.VerifyAssertions) { - if (!(instr instanceof ARM_Instructions.SoftwareInterrupt)) { - throw new Error("The current instruction is not a valid system call."); - } + DBT._assert(instr instanceof ARM_Instructions.SoftwareInterrupt); } //Thumb system calls start from 0, while ARM calls start from 0x900000. Modified: src/org/binarytranslator/generic/decoder/DecoderUtils.java =================================================================== --- src/org/binarytranslator/generic/decoder/DecoderUtils.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/generic/decoder/DecoderUtils.java 2007-05-10 15:21:58 UTC (rev 111) @@ -447,6 +447,7 @@ * @return the next block */ public OPT_BasicBlock getNextBlock() { + return nextBlock; } Modified: src/org/binarytranslator/generic/memory/AutoMappingMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/AutoMappingMemory.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/generic/memory/AutoMappingMemory.java 2007-05-10 15:21:58 UTC (rev 111) @@ -2,8 +2,6 @@ import java.io.RandomAccessFile; -import org.binarytranslator.vmInterface.TranslationHelper; -import org.jikesrvm.classloader.VM_MethodReference; /** * A memory implementation that will automatically map pages into memory, as soon @@ -31,10 +29,6 @@ return mem.equals(arg0); } - public VM_MethodReference getMethodRef(int callAddress) { - return mem.getMethodRef(callAddress); - } - public int getPageSize() { return mem.getPageSize(); } @@ -43,10 +37,6 @@ return mem.hashCode(); } - public void initTranslate(TranslationHelper helper) { - mem.initTranslate(helper); - } - public boolean isMapped(int addr) { return mem.isMapped(addr); } Modified: src/org/binarytranslator/generic/memory/DebugMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/DebugMemory.java 2007-05-09 17:28:51 UTC (rev 110) +++ src/org/binarytranslator/generic/memory/DebugMemory.java 2007-05-10 15:21:58 UTC (rev 111) @@ -470,7 +470,7 @@ * @return the result */ public int load32(int addr) { - return (loadSigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) + return (loadUnsigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) | (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-05-17 16:31:40
|
Revision: 120 http://svn.sourceforge.net/pearcolator/?rev=120&view=rev Author: michael_baer Date: 2007-05-17 09:31:37 -0700 (Thu, 17 May 2007) Log Message: ----------- General changes to the dynamic translator: - Generalized & harmonized the set of functions used to build a trace - enabled the use of branch profiling for all ISAs - many code cleanups & refactorings ARM DBT changes: - Not returning from the trace on most branches - Using branch profiling - added support for more instruction types Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java src/org/binarytranslator/arch/x86/decoder/X862IR.java src/org/binarytranslator/arch/x86/decoder/X86_DecodedOperand.java src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java src/org/binarytranslator/arch/x86/decoder/X86_ModRM_Decoder.java src/org/binarytranslator/generic/branch/BranchLogic.java src/org/binarytranslator/generic/decoder/InstructionDecoder.java src/org/binarytranslator/generic/memory/CallBasedMemory.java src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java src/org/binarytranslator/generic/memory/Memory.java src/org/binarytranslator/generic/os/process/ProcessSpace.java src/org/binarytranslator/vmInterface/DBT_Trace.java Added Paths: ----------- src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java src/org/binarytranslator/generic/os/abi/linux/filesystem/RemappingFilesystem.java Removed Paths: ------------- src/org/binarytranslator/generic/decoder/DecoderUtils.java src/org/binarytranslator/vmInterface/TranslationHelper.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-16 18:16:21 UTC (rev 119) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-17 16:31:37 UTC (rev 120) @@ -7,7 +7,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; -import org.binarytranslator.generic.decoder.DecoderUtils; +import org.binarytranslator.generic.decoder.AbstractCodeTranslator; import org.binarytranslator.generic.decoder.Laziness; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_FieldReference; @@ -17,7 +17,7 @@ import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.ir.*; -public class ARM2IR extends DecoderUtils implements OPT_HIRGenerator { +public class ARM2IR extends AbstractCodeTranslator implements OPT_HIRGenerator { /** Mapping of ARM registers to HIR registers */ private OPT_Register regMap[] = new OPT_Register[16]; @@ -128,7 +128,6 @@ if (DBT.VerifyAssertions) DBT._assert(registers_overflowFlag_Fref != null); } - public ARM2IR(OPT_GenerationContext context) { super(context); @@ -172,7 +171,7 @@ VM_FieldReference requestedMode_FieldReference = VM_FieldReference.findOrCreate(OperatingMode_TypeRef, VM_Atom.findOrCreateAsciiAtom(mode.name()), VM_Atom.findOrCreateAsciiAtom("Lorg/binarytranslator/arch/arm/os/process/ARM_Registers/OperatingMode;")).asFieldReference(); //Finally, use a getfield to grab the (static) member field - appendInstructionToCurrentBlock(GetField.create(GETFIELD, result, + appendInstruction(GetField.create(GETFIELD, result, null, new OPT_AddressConstantOperand(requestedMode_FieldReference .peekResolvedField().getOffset()), new OPT_LocationOperand( requestedMode_FieldReference), new OPT_TrueGuardOperand())); @@ -190,7 +189,7 @@ if (ps_registers == null) { ps_registersOp = gc.temps.makeTemp(registersTref); ps_registers = ps_registersOp.register; - appendInstructionToCurrentBlock(GetField.create(GETFIELD, ps_registersOp, + appendInstruction(GetField.create(GETFIELD, ps_registersOp, gc.makeLocal(1, psTref), new OPT_AddressConstantOperand(registersFref .peekResolvedField().getOffset()), new OPT_LocationOperand( registersFref), new OPT_TrueGuardOperand())); @@ -218,19 +217,19 @@ //store the carry flag OPT_RegisterOperand flag = new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); //store the negative flag flag = new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); //store the zero flag flag = new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); //store the overflow flag flag = new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(PutField.create(PUTFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); } public void fillAllFlags() { @@ -247,19 +246,19 @@ //get the carry flag OPT_RegisterOperand flag = new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_carryFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_carryFlag_Fref), new OPT_TrueGuardOperand()) ); //get the negative flag flag = new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_negativeFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_negativeFlag_Fref), new OPT_TrueGuardOperand()) ); //get the zero flag flag = new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_zeroFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_zeroFlag_Fref), new OPT_TrueGuardOperand()) ); //get the overflow flag flag = new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); - appendInstructionToCurrentBlock(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); + appendInstruction(GetField.create(GETFIELD, flag, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_overflowFlag_Fref.peekResolvedField().getOffset()), new OPT_LocationOperand(registers_overflowFlag_Fref), new OPT_TrueGuardOperand()) ); } @Override @@ -273,7 +272,7 @@ if (ps_registers_regs == null) { ps_registers_regsOp = gc.temps.makeTemp(registers_regs_Tref); - appendInstructionToCurrentBlock(GetField.create(GETFIELD, + appendInstruction(GetField.create(GETFIELD, ps_registers_regsOp, ps_registersOp.copyRO(), new OPT_AddressConstantOperand(registers_regs_Fref.peekResolvedField() .getOffset()), new OPT_LocationOperand(registers_regs_Fref), @@ -292,7 +291,7 @@ } else { regOp = new OPT_RegisterOperand(regMap[i], VM_TypeReference.Int); } - appendInstructionToCurrentBlock(ALoad.create(INT_ALOAD, regOp, + appendInstruction(ALoad.create(INT_ALOAD, regOp, ps_registers_regsOp.copyRO(), new OPT_IntConstantOperand(i), new OPT_LocationOperand(VM_TypeReference.Int), new OPT_TrueGuardOperand())); @@ -357,7 +356,7 @@ // never used if ((DBT_Options.singleInstrTranslation == false) || (regUsed[i] == true)) { - appendInstructionToCurrentBlock(AStore.create(INT_ASTORE, + appendInstruction(AStore.create(INT_ASTORE, new OPT_RegisterOperand(regMap[i], VM_TypeReference.Int), ps_registers_regsOp.copyRO(), new OPT_IntConstantOperand(i), new OPT_LocationOperand(VM_TypeReference.Int), @@ -423,23 +422,23 @@ Call.setAddress(s, new OPT_AddressConstantOperand(rotateRightMethod .getOffset())); - appendInstructionToCurrentBlock(s); + appendInstruction(s); } protected void appendBitTest(OPT_RegisterOperand target, OPT_Operand wordToTest, OPT_Operand bit) { if (DBT.VerifyAssertions) DBT._assert(wordToTest != target && bit != target); - appendInstructionToCurrentBlock(Binary.create(OPT_Operators.INT_SHL, target, new OPT_IntConstantOperand(1), bit)); - appendInstructionToCurrentBlock(Binary.create(OPT_Operators.INT_AND, target, wordToTest, target)); - appendInstructionToCurrentBlock(BooleanCmp.create(OPT_Operators.BOOLEAN_CMP_INT, target, target, new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(Binary.create(OPT_Operators.INT_SHL, target, new OPT_IntConstantOperand(1), bit)); + appendInstruction(Binary.create(OPT_Operators.INT_AND, target, wordToTest, target)); + appendInstruction(BooleanCmp.create(OPT_Operators.BOOLEAN_CMP_INT, target, target, new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand())); } protected void appendBitTest(OPT_RegisterOperand target, OPT_Operand wordToTest, int bit) { if (DBT.VerifyAssertions) DBT._assert(wordToTest != target); if (DBT.VerifyAssertions) DBT._assert(bit <= 31 && bit >= 0); - appendInstructionToCurrentBlock(Binary.create(OPT_Operators.INT_AND, target, wordToTest, new OPT_IntConstantOperand(1 << bit))); - appendInstructionToCurrentBlock(BooleanCmp.create(OPT_Operators.BOOLEAN_CMP_INT, target, target, new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(Binary.create(OPT_Operators.INT_AND, target, wordToTest, new OPT_IntConstantOperand(1 << bit))); + appendInstruction(BooleanCmp.create(OPT_Operators.BOOLEAN_CMP_INT, target, target, new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand())); } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-16 18:16:21 UTC (rev 119) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-17 16:31:37 UTC (rev 120) @@ -8,6 +8,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; +import org.binarytranslator.generic.branch.BranchLogic.BranchType; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_MemberReference; import org.jikesrvm.classloader.VM_Method; @@ -15,17 +16,18 @@ import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.opt.ir.*; -/** - */ public class ARM_Translator implements OPT_Operators { /** The process space that we're interpreting.*/ protected final ARM_ProcessSpace ps; + /** The ARM translation class. */ protected final ARM2IR arm2ir; + /** The current laziness state. */ protected ARM_Laziness lazy; + /** The current pc that we're translating. */ protected int pc; /** A "quick" pointer to the ARM registers within the process space*/ @@ -53,6 +55,19 @@ return instr.getSuccessor(pc); } + /** + * Creates an HIR instruction that will call method <code>methodName</code> in the current ARM registers class, + * which has the signature <code>signature</code> and takes <code>numParameters</code> parameters. + * + * @param methodName + * The name of the method to call. + * @param signature + * The method's signature + * @param numParameters + * The number of parameters the method takes. + * @return + * An HIR instruction that will call the given method. + */ private OPT_Instruction createCallToRegisters(String methodName, String signature, int numParameters) { VM_TypeReference RegistersType = VM_TypeReference @@ -79,19 +94,28 @@ return call; } + /** Some ARM instructions can use several addressing modes. Therefore, the ARM Decoder uses an + * {@link OperandWrapper}, that abstracts these differences. The <code>ResolvedOperand</code> class + * can be used to resolve an <code>OperandWrapper</code> into an actual HIR operand.*/ private abstract static class ResolvedOperand { + /** Stores the value that the operand resolves to. */ protected OPT_Operand value; + /** A backlink to the {@link ARM_Translator} class that is using this ResolvedOperand instance. */ protected ARM_Translator translator; - public static OPT_Operand resolveAndStoreShifterCarryOutToCarry( - ARM_Translator translator, OperandWrapper operand) { - - ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(translator, operand); - return result.getValue(); - } - + /** + * Call this function to create code that converts the <code>operand</code> into an + * HIR <code>OPT_Operand</code>. + * + * @param translator + * + * @param operand + * The operand that is to be converted. + * @return + * An HIR operand that represents the resolved operand. + */ public static OPT_Operand resolve(ARM_Translator translator, OperandWrapper operand) { ResolvedOperand result = new ResolvedOperand_WithoutShifterCarryOut( @@ -99,10 +123,30 @@ return result.getValue(); } + /** + * Works similar to {@link #resolve(ARM_Translator, OperandWrapper)}, but also calculates the + * shifter-carry-out that the ARM barell shifter would produce while resolving this operand. + * The shifter-carry-out is directly written into the <code>translator</code>'s carry flag. + * @param translator + * The translator instance within which the code for the said conversion is to be created. + * @param operand + * The operand that is to be converted. + * @return + * An HIR operand that represents the resolved operand. + */ + public static OPT_Operand resolveAndStoreShifterCarryOutToCarry( + ARM_Translator translator, OperandWrapper operand) { + + ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(translator, operand); + return result.getValue(); + } + public final OPT_Operand getValue() { return value; } + /** A subclass that resolves an {@link OperandWrapper} without calculating the shifter + * carry out produced by ARM's barrel shifter. */ private static class ResolvedOperand_WithoutShifterCarryOut extends ResolvedOperand { @@ -173,7 +217,7 @@ // the amount of shifting is determined by a register shiftAmount = translator.arm2ir.getRegister(operand.getShiftingRegister()); OPT_RegisterOperand shiftAmountAsByte = translator.arm2ir.getTempInt(7); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_AND, shiftAmountAsByte, shiftAmount, new OPT_IntConstantOperand(0xFF))); + translator.arm2ir.appendInstruction(Binary.create(INT_AND, shiftAmountAsByte, shiftAmount, new OPT_IntConstantOperand(0xFF))); shiftAmount = shiftAmountAsByte; } @@ -196,18 +240,18 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount)); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create( + translator.arm2ir.appendInstruction(Binary.create( INT_SHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(31))); break; @@ -218,24 +262,22 @@ block2 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - //current block curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); - //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); break; case LSR: @@ -247,23 +289,22 @@ block2 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); block1 = translator.arm2ir.createBlockAfterCurrentNotInCFG(); - //current block curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); break; case ROR: @@ -285,13 +326,13 @@ curBlock.deleteNormalOut(); curBlock.insertOut(nextBlock); curBlock.insertOut(block1); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); + translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); break; default: @@ -303,7 +344,10 @@ return resultRegister; } } - + + /** + * This class resolves an {@link OperandWrapper} and also writes the shifter carry out, as + * produced by ARM's barrel shifter, into the Carry flag.*/ private static class ResolvedOperand_WithShifterCarryOut extends ResolvedOperand { @@ -323,7 +367,7 @@ OPT_Operand shifterCarryOut = new OPT_IntConstantOperand(((operand.getImmediate() & 0x80000000) != 0) ? 1 : 0); //otherwise there is no shifter carry out - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, carryFlag, shifterCarryOut)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, carryFlag, shifterCarryOut)); } return; @@ -386,7 +430,7 @@ // the amount of shifting is determined by a register shiftAmount = translator.arm2ir.getRegister(operand.getShiftingRegister()); OPT_RegisterOperand shiftAmountAsByte = translator.arm2ir.getTempInt(7); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_AND, shiftAmountAsByte, shiftAmount, new OPT_IntConstantOperand(0xFF))); + translator.arm2ir.appendInstruction(Binary.create(INT_AND, shiftAmountAsByte, shiftAmount, new OPT_IntConstantOperand(0xFF))); shiftAmount = shiftAmountAsByte; } @@ -409,33 +453,33 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block4); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block4.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block4.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - shift < 32 && shift != 0 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount) ); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount) ); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - shift >= 32 translator.arm2ir.setCurrentBlock(block3); block3.insertOut(nextBlock); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_MUL, resultRegister, getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_MUL, resultRegister, getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 4 - shift == 0 translator.arm2ir.setCurrentBlock(block4); block4.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); break; case LSL: @@ -453,45 +497,45 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block6); curBlock.insertOut(block1); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - Shift >= 32 translator.arm2ir.setCurrentBlock(block3); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); block3.insertOut(block4); block3.insertOut(block5); //block 4 - Shift > 32 translator.arm2ir.setCurrentBlock(block4); block4.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 5 - Shift == 32 translator.arm2ir.setCurrentBlock(block5); block5.insertOut(nextBlock); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 0); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 6 - shift == 0 translator.arm2ir.setCurrentBlock(block6); block6.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); break; case LSR: @@ -510,45 +554,45 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block6); curBlock.insertOut(block1); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1))); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1))); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - Shift >= 32 translator.arm2ir.setCurrentBlock(block3); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); block3.insertOut(block4); block3.insertOut(block5); //block 4 - Shift > 32 translator.arm2ir.setCurrentBlock(block4); block4.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, getShifterCarryOutTarget(), new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 5 - Shift == 32 translator.arm2ir.setCurrentBlock(block5); block5.insertOut(nextBlock); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 6 - shift == 0 translator.arm2ir.setCurrentBlock(block6); block6.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); break; case ROR: @@ -562,20 +606,20 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand, shiftAmount); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_AND, tmp, tmp, new OPT_IntConstantOperand(0x1F)) ); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); + translator.arm2ir.appendInstruction(Binary.create(INT_AND, tmp, tmp, new OPT_IntConstantOperand(0x1F)) ); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstructionToCurrentBlock(Goto.create(GOTO, nextBlock.makeJumpTarget())); + translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 translator.arm2ir.setCurrentBlock(block2); - translator.arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); break; case RRX: @@ -589,13 +633,13 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); + translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); //nextBlock translator.arm2ir.setCurrentBlock(nextBlock); @@ -640,29 +684,17 @@ public int getSuccessor(int pc) { //if this instruction is not a jump, then we can tell what the next instruction will be. - if (conditionalInstruction.getSuccessor(pc) == pc + 4) - return pc + 4; - else - return -1; + return pc + 4; } public void translate() { //conditionals are implemented easily: if the condition does not hold, then just //jump to the block following the conditional instruction - OPT_BasicBlock nextInstruction; - OPT_BasicBlock condBlock; - - if (getSuccessor(pc) != -1) { - nextInstruction = arm2ir.getNextBlock(); - condBlock = arm2ir.createBlockAfterCurrent(); - condBlock.insertOut(nextInstruction); - } - else { - nextInstruction = arm2ir.createBlockAfterCurrent(); - condBlock = arm2ir.createBlockAfterCurrent(); - } - + OPT_BasicBlock nextInstruction = arm2ir.getNextBlock(); + OPT_BasicBlock condBlock = arm2ir.createBlockAfterCurrent(); + arm2ir.getCurrentBlock().deleteNormalOut(); arm2ir.getCurrentBlock().insertOut(nextInstruction); + arm2ir.getCurrentBlock().insertOut(condBlock); switch (conditionalInstruction.getCondition()) { case AL: @@ -745,11 +777,6 @@ arm2ir.setCurrentBlock(condBlock); conditionalInstruction.translate(); - - if (getSuccessor(pc) == -1) { - arm2ir.setCurrentBlock(nextInstruction); - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, new OPT_IntConstantOperand(pc+4)); - } } private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand operand, OPT_ConditionOperand condition) { @@ -759,7 +786,7 @@ private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand lhs, OPT_ConditionOperand condition, OPT_Operand rhs) { condition = condition.flipCode(); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } private void translateCondition_HI(OPT_BasicBlock nextInstruction) { @@ -768,10 +795,10 @@ OPT_Operand zero = arm2ir.getZeroFlag(); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); - arm2ir.appendInstructionToCurrentBlock(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, + arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } private void translateCondition_LS(OPT_BasicBlock nextInstruction) { @@ -780,10 +807,10 @@ OPT_Operand zero = arm2ir.getZeroFlag(); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); - arm2ir.appendInstructionToCurrentBlock(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, + arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } private void translateCondition_GT(OPT_BasicBlock nextInstruction) { @@ -793,10 +820,10 @@ OPT_Operand zero = arm2ir.getZeroFlag(); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); - arm2ir.appendInstructionToCurrentBlock(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, + arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, overflow, OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } private void translateCondition_LE(OPT_BasicBlock nextInstruction) { @@ -806,10 +833,10 @@ OPT_Operand zero = arm2ir.getZeroFlag(); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); - arm2ir.appendInstructionToCurrentBlock(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, + arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, overflow, OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } public Condition getCondition() { @@ -854,7 +881,7 @@ public abstract void translate(); /** Sets the processor flags according to the result of adding <code>lhs</code> and <code>rhs</code>.*/ - protected final void setAddResult(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { + protected final void setAddResult(OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs) { if (updateConditionCodes) { if (Rd != 15) { @@ -862,14 +889,20 @@ } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstructionToCurrentBlock(s); + arm2ir.appendInstruction(s); } } - arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); - - if (Rd == 15) - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + if (Rd == 15) { + + if (updateConditionCodes) + arm2ir.appendDynamicJump(result, lazy, BranchType.INDIRECT_BRANCH); + else + arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + } + else { + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + } } /** @@ -883,24 +916,24 @@ */ protected final void setAddFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { //set the carry flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, OPT_ConditionOperand.CARRY_FROM_ADD(), new OPT_BranchProfileOperand())); //set the overflow flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs, rhs, OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); //set the negative flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ - protected final void setSubResult(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { + protected final void setSubResult(OPT_RegisterOperand result, OPT_Operand lhs, OPT_Operand rhs) { if (updateConditionCodes) { if (Rd != 15) { @@ -908,14 +941,20 @@ } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstructionToCurrentBlock(s); + arm2ir.appendInstruction(s); } } - - arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); - - if (Rd == 15) - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + + if (Rd == 15) { + + if (updateConditionCodes) + arm2ir.appendDynamicJump(result, lazy, BranchType.INDIRECT_BRANCH); + else + arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + } + else { + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + } } /** @@ -929,20 +968,20 @@ */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { //set the carry flag to not(Borrow) - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, OPT_ConditionOperand.BORROW_FROM_SUB(), new OPT_BranchProfileOperand())); - arm2ir.appendInstructionToCurrentBlock(Unary.create(BOOLEAN_NOT, arm2ir.getCarryFlag(), arm2ir.getCarryFlag())); + arm2ir.appendInstruction(Unary.create(BOOLEAN_NOT, arm2ir.getCarryFlag(), arm2ir.getCarryFlag())); //set the overflow flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs, rhs, OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); //set the negative flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } @@ -975,21 +1014,36 @@ } /** Sets the condition field for logical operations. */ - protected final void setLogicalResult(OPT_Operand result) { + protected final void setLogicalResult(OPT_RegisterOperand result) { if (updateConditionCodes) { if (Rd != 15) { setLogicalFlags(result); } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstructionToCurrentBlock(s); + arm2ir.appendInstruction(s); } } - arm2ir.appendInstructionToCurrentBlock(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); - if (Rd == 15) - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + + if (Rd == 15) { + if (updateConditionCodes) { + arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + } + else { + BranchType branchType = BranchType.INDIRECT_BRANCH; + + //Mark "MOV pc, lr" instructions as returns + if (opcode == Opcode.MOV && operand2.getType() == OperandWrapper.Type.Register && operand2.getRegister() == ARM_Registers.LR) + branchType = BranchType.RETURN; + + arm2ir.appendDynamicJump(result, lazy, branchType); + } + } + else { + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + } } /** @@ -1001,11 +1055,11 @@ //the shifter carry out has already been set during the resolve-phase //set the negative flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag - arm2ir.appendInstructionToCurrentBlock(BooleanCmp.create( + arm2ir.appendInstruction(BooleanCmp.create( BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -1021,7 +1075,7 @@ public void translate() { OPT_RegisterOperand result = getResultRegister(); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_AND, result, resolveOperand1(), resolveOperand2())); + arm2ir.appendInstruction(Binary.create(INT_AND, result, resolveOperand1(), resolveOperand2())); setLogicalResult(result); } @@ -1038,7 +1092,7 @@ public void translate() { OPT_RegisterOperand result = getResultRegister(); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_XOR, result, resolveOperand1(), resolveOperand2())); + arm2ir.appendInstruction(Binary.create(INT_XOR, result, resolveOperand1(), resolveOperand2())); setLogicalResult(result); } @@ -1057,7 +1111,7 @@ OPT_Operand operand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, result, operand1, operand2)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); setAddResult(result, operand1, operand2); } @@ -1076,7 +1130,7 @@ OPT_Operand operand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SUB, result, operand1, operand2)); + arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); setSubResult(result, operand1, operand2); } @@ -1095,7 +1149,7 @@ OPT_Operand operand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SUB, result, operand2, operand1)); + arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand2, operand1)); setSubResult(result, operand2, operand1); } @@ -1121,13 +1175,13 @@ OPT_BasicBlock addWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); //Is the carry set at all? if not, just jump to addWithoutCarry - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, result, operand1, operand2)); - arm2ir.appendInstructionToCurrentBlock(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. arm2ir.setCurrentBlock(addWithCarry); - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_ADD, result, result, new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, result, new OPT_IntConstantOperand(1))); addWithCarry.insertOut(addWithoutCarry); //Finally, add the second operands to the result @@ -1152,13 +1206,13 @@ OPT_BasicBlock subWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); //Is the carry set? if yes, just jump to subWithoutCarry - arm2ir.appendInstructionToCurrentBlock(Binary.create(INT_SUB, result, operand1, operand2)); - arm2... [truncated message content] |
From: <mic...@us...> - 2007-05-18 17:15:07
|
Revision: 123 http://svn.sourceforge.net/pearcolator/?rev=123&view=rev Author: michael_baer Date: 2007-05-18 10:13:21 -0700 (Fri, 18 May 2007) Log Message: ----------- Further refined branch resolution: - centralized the decision on whether to include a branch target into the trace or not - harmonized the way branch targets are resolved and the call interface to the decoder - re-introduced a code cache in the ProcessSpace class Misc. changes: - allowing custom functions calls within traces (untested) ARM changes: - fixed a bug where flags in RSBS would be set incorrectly Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java src/org/binarytranslator/arch/x86/decoder/X862IR.java src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java src/org/binarytranslator/generic/execution/DynamicTranslationController.java src/org/binarytranslator/generic/memory/CallBasedMemory.java src/org/binarytranslator/generic/memory/DebugMemory.java src/org/binarytranslator/generic/memory/MemoryMapException.java src/org/binarytranslator/generic/os/process/ProcessSpace.java src/org/binarytranslator/vmInterface/DBT_Trace.java Added Paths: ----------- src/org/binarytranslator/generic/decoder/CodeCache.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/DBT_Options.java 2007-05-18 17:13:21 UTC (rev 123) @@ -17,8 +17,10 @@ * Options for controlling the emulator */ public class DBT_Options { - // -oO Runtime settings Oo- + /** Remove features that will only work on jikes? */ + public final static boolean buildForSunVM = true; + /** * Debug binary loading */ @@ -69,19 +71,10 @@ */ public static boolean plantUncaughtBranchWatcher = false; - /** - * Should all branches (excluding to lr and ctr) be resolved in one big go or - * one at at a time - */ - public static boolean resolveBranchesAtOnce = true; + /** Should direct branches be resolved before dynamic branches? */ + public static boolean resolveDirectBranchesFirst = true; /** - * Should procedures (branches to ctr and lr) be given precedent over more - * local branches - */ - public static boolean resolveProceduresBeforeBranches = true; - - /** * Use global branch information rather than local (within the trace) * information when optimisation level is greater than or equal to this value */ @@ -231,14 +224,8 @@ instrOpt2 = Integer.parseInt(value); } else if (arg.equalsIgnoreCase("-X:dbt:singleInstrTranslation")) { singleInstrTranslation = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:resolveBranchesAtOnce")) { - resolveBranchesAtOnce = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:resolveBranchesAtOnce")) { - resolveBranchesAtOnce = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:resolveProceduresBeforeBranches")) { - resolveProceduresBeforeBranches = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:resolveProceduresBeforeBranches")) { - resolveProceduresBeforeBranches = Boolean.parseBoolean(value); + } else if (arg.equalsIgnoreCase("-X:dbt:resolveDirectBranchesFirst")) { + resolveDirectBranchesFirst = Boolean.parseBoolean(value); } else if (arg.equalsIgnoreCase("-X:dbt:gdbStub")) { gdbStub = Boolean.parseBoolean(value); } else if (arg.equalsIgnoreCase("-X:dbt:gdbStubPort")) { Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/Main.java 2007-05-18 17:13:21 UTC (rev 123) @@ -10,11 +10,15 @@ import java.io.File; -import org.binarytranslator.arch.arm.decoder.Utils; import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; import org.binarytranslator.generic.execution.InterpreterController; +import org.binarytranslator.generic.execution.ThreadedInterpretationController; +import org.binarytranslator.generic.execution.ThreadedInterpretationController2; +import org.binarytranslator.generic.execution.ThreadedInterpretationController3; +import org.binarytranslator.generic.execution.ThreadedInterpretationController4; +import org.binarytranslator.generic.execution.ThreadedInterpretationController5; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -98,15 +102,18 @@ //Create an execution controller and pass execution on to it ExecutionController controller; - if (DBT_Options.gdbStub) { - controller = new GdbController(DBT_Options.gdbStubPort, ps); + if (DBT_Options.buildForSunVM) { + controller = new InterpreterController(ps); } else { - controller = new DynamicTranslationController(ps); + if (DBT_Options.gdbStub) { + controller = new GdbController(DBT_Options.gdbStubPort, ps); + } + else { + controller = new DynamicTranslationController(ps); + } } - - //controller = new InterpreterController(ps); controller.run(); System.out.println("\nProgram has finished."); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-18 17:13:21 UTC (rev 123) @@ -9,6 +9,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; import org.binarytranslator.generic.decoder.AbstractCodeTranslator; import org.binarytranslator.generic.decoder.Laziness; +import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_FieldReference; import org.jikesrvm.classloader.VM_MemberReference; @@ -129,8 +130,8 @@ if (DBT.VerifyAssertions) DBT._assert(registers_overflowFlag_Fref != null); } - public ARM2IR(OPT_GenerationContext context) { - super(context); + public ARM2IR(OPT_GenerationContext context, DBT_Trace trace) { + super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-18 17:13:21 UTC (rev 123) @@ -889,16 +889,16 @@ } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstruction(s); + arm2ir.appendCustomCall(s); } } if (Rd == 15) { if (updateConditionCodes) - arm2ir.appendDynamicJump(result, lazy, BranchType.INDIRECT_BRANCH); + arm2ir.appendBranch(result, lazy, BranchType.INDIRECT_BRANCH); else - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + arm2ir.appendTraceExit(lazy, result); } else { arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); @@ -941,16 +941,15 @@ } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstruction(s); + arm2ir.appendCustomCall(s); } } if (Rd == 15) { - if (updateConditionCodes) - arm2ir.appendDynamicJump(result, lazy, BranchType.INDIRECT_BRANCH); + arm2ir.appendBranch(result, lazy, BranchType.INDIRECT_BRANCH); else - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + arm2ir.appendTraceExit(lazy, result); } else { arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); @@ -968,9 +967,9 @@ */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { //set the carry flag to not(Borrow) + OPT_ConditionOperand notBorrowFromSub = OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(); arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, OPT_ConditionOperand.BORROW_FROM_SUB(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(Unary.create(BOOLEAN_NOT, arm2ir.getCarryFlag(), arm2ir.getCarryFlag())); + BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, notBorrowFromSub, new OPT_BranchProfileOperand())); //set the overflow flag arm2ir.appendInstruction(BooleanCmp.create( @@ -1021,15 +1020,13 @@ setLogicalFlags(result); } else { OPT_Instruction s = createCallToRegisters("restoreSPSR2CPSR", "()V", 0); - arm2ir.appendInstruction(s); + arm2ir.appendCustomCall(s); } } - - if (Rd == 15) { if (updateConditionCodes) { - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, result); + arm2ir.appendTraceExit(lazy, result); } else { BranchType branchType = BranchType.INDIRECT_BRANCH; @@ -1038,7 +1035,7 @@ if (opcode == Opcode.MOV && operand2.getType() == OperandWrapper.Type.Register && operand2.getRegister() == ARM_Registers.LR) branchType = BranchType.RETURN; - arm2ir.appendDynamicJump(result, lazy, branchType); + arm2ir.appendBranch(result, lazy, branchType); } } else { @@ -1284,6 +1281,7 @@ OPT_Operand operand1 = resolveOperand1(); OPT_Operand operand2 = resolveOperand2(); OPT_RegisterOperand result = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); setSubFlags(result, operand1, operand2); } @@ -1302,6 +1300,7 @@ OPT_Operand operand1 = resolveOperand1(); OPT_Operand operand2 = resolveOperand2(); OPT_RegisterOperand result = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); setAddFlags(result, operand1, operand2); } @@ -1358,6 +1357,7 @@ OPT_RegisterOperand result = getResultRegister(); OPT_RegisterOperand tmp = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Unary.create(INT_NOT, tmp, operand2)); arm2ir.appendInstruction(Binary.create(INT_AND, result, operand1, tmp)); setLogicalResult(result); @@ -1494,7 +1494,7 @@ //This instruction gets very complex when forceUser is set, which is why we are interpreting that special and rare instruction if (forceUser) { arm2ir.appendInterpretedInstruction(pc, lazy); - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, arm2ir.getRegister(ARM_Registers.PC)); + arm2ir.appendTraceExit(lazy, arm2ir.getRegister(ARM_Registers.PC)); return; } @@ -1571,7 +1571,7 @@ switchToThumbBlock.insertOut(finishInstruction); OPT_Instruction call_setThumbMode = createCallToRegisters("setThumbMode", "(Z)V", 1); Call.setParam(call_setThumbMode, 1, new OPT_IntConstantOperand(1)); - arm2ir.appendInstruction(call_setThumbMode); + arm2ir.appendCustomCall(call_setThumbMode); arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); //No, don't switch to thumb mode @@ -1580,12 +1580,12 @@ arm2ir.appendInstruction(Binary.create(INT_AND, regPC, regPC, new OPT_IntConstantOperand(0xFFFFFFFE))); OPT_Instruction call_setArmMode = createCallToRegisters("setThumbMode", "(Z)V", 1); Call.setParam(call_setArmMode, 1, new OPT_IntConstantOperand(0)); - arm2ir.appendInstruction(call_setArmMode); + arm2ir.appendCustomCall(call_setArmMode); arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); //according to the APCS, these types of instructions are usually function returns arm2ir.setCurrentBlock(finishInstruction); - arm2ir.appendDynamicJump(regPC, lazy, BranchType.RETURN); + arm2ir.appendBranch(regPC, lazy, BranchType.RETURN); return; } } else { @@ -1658,9 +1658,12 @@ if (link) { arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(ARM_Registers.LR), new OPT_IntConstantOperand(pc + 4))); } + else { + //we should never be returning from the goto + arm2ir.getCurrentBlock().deleteNormalOut(); + } - arm2ir.getCurrentBlock().deleteNormalOut(); - arm2ir.appendGoto(pc + getOffset() + 8, lazy, link ? BranchType.CALL : BranchType.DIRECT_BRANCH); + arm2ir.appendBranch(pc + getOffset() + 8, lazy, link ? BranchType.CALL : BranchType.DIRECT_BRANCH); } public int getSuccessor(int pc) { @@ -1718,11 +1721,11 @@ //set the correct processor mode (thumb or not) OPT_Instruction s = createCallToRegisters("setThumbMode", "(Z)V", 1); Call.setParam(s, 1, enableThumb); - arm2ir.appendInstruction(s); + arm2ir.appendCustomCall(s); //jump to the target address. Because we might have switched to thumb mode, we are //ending the trace with this method - arm2ir.setReturnValueResolveLazinessAndBranchToFinish(lazy, targetAddress); + arm2ir.appendTraceExit(lazy, targetAddress); } public int getSuccessor(int pc) { @@ -1856,7 +1859,7 @@ } Call.setResult(call, psrValue); - arm2ir.appendInstruction(call); + arm2ir.appendCustomCall(call); } public int getSuccessor(int pc) { @@ -1892,7 +1895,7 @@ public void translate() { arm2ir.appendSystemCall(lazy, pc); - arm2ir.appendDynamicJump(arm2ir.getRegister(ARM_Registers.PC), lazy, BranchType.INDIRECT_BRANCH); + arm2ir.appendBranch(arm2ir.getRegister(ARM_Registers.PC), lazy, BranchType.INDIRECT_BRANCH); } public int getSuccessor(int pc) { @@ -1957,12 +1960,12 @@ currentOperatingMode = arm2ir.getTempOperatingMode(); Call.setResult(call_getOperatingMode, currentOperatingMode); - arm2ir.appendInstruction(call_getOperatingMode); + arm2ir.appendCustomCall(call_getOperatingMode); OPT_Instruction call_setOperatingModeWithoutRegisterLayout = createCallToRegisters("setOperatingModeWithoutRegisterLayout", "(A)", 1); Call.setParam(call_setOperatingModeWithoutRegisterLayout, 1, arm2ir.getTempOperatingMode(OperatingMode.USR)); - arm2ir.appendInstruction(call_setOperatingModeWithoutRegisterLayout); + arm2ir.appendCustomCall(call_setOperatingModeWithoutRegisterLayout); } //get the address of the memory, that we're supposed access @@ -2040,7 +2043,7 @@ if (forceUserMode) { OPT_Instruction call_setOperatingModeWithoutRegisterLayout = createCallToRegisters("setOperatingModeWithoutRegisterLayout", "(A)", 1); Call.setParam(call_setOperatingModeWithoutRegisterLayout, 1, currentOperatingMode); - arm2ir.appendInstruction(call_setOperatingModeWithoutRegisterLayout); + arm2ir.appendCustomCall(call_setOperatingModeWithoutRegisterLayout); } //should the memory address, which we accessed, be written back into a register? @@ -2060,7 +2063,7 @@ if (isLoad && Rd == ARM_Registers.PC) { //we are actually loading to the program counter here - arm2ir.appendDynamicJump(arm2ir.getRegister(Rd), lazy, BranchType.INDIRECT_BRANCH); + arm2ir.appendBranch(arm2ir.getRegister(Rd), lazy, BranchType.INDIRECT_BRANCH); } } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) @@ -8,9 +8,11 @@ import org.binarytranslator.arch.arm.os.process.image.ARM_ImageProcessSpace; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.ByteAddressedMemory; import org.binarytranslator.generic.memory.DebugMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; +import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; import org.vmmagic.pragma.Uninterruptible; @@ -37,7 +39,11 @@ protected ARM_ProcessSpace() { registers = new ARM_Registers(); - memory = new DebugMemory(); + + if (DBT_Options.buildForSunVM) + memory = new DebugMemory(); + else + memory = new ByteAddressedMemory(); } /** @@ -48,8 +54,8 @@ * the generation context for the HIR generation * @return a HIR generator */ - public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { - return new ARM2IR(context); + public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context, DBT_Trace trace) { + return new ARM2IR(context, trace); } /** Modified: src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java =================================================================== --- src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/ppc/decoder/PPC2IR.java 2007-05-18 17:13:21 UTC (rev 123) @@ -17,6 +17,7 @@ import org.binarytranslator.generic.decoder.AbstractCodeTranslator; import org.binarytranslator.generic.decoder.Laziness; import org.binarytranslator.vmInterface.DBT_OptimizingCompilerException; +import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_FieldReference; import org.jikesrvm.classloader.VM_MemberReference; @@ -253,8 +254,8 @@ * Construct the PPC2IR object for the generation context; then we'll be ready * to start generating the HIR. */ - public PPC2IR(OPT_GenerationContext context) { - super(context); + public PPC2IR(OPT_GenerationContext context, DBT_Trace trace) { + super(context, trace); // Create register maps PPC -> OPT_Register intRegMap = new OPT_Register[32]; intRegInUseMap = new boolean[32]; Modified: src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-05-18 17:13:21 UTC (rev 123) @@ -4026,7 +4026,7 @@ branchAddress = ppc2ir.getLRRegister(); } - ppc2ir.appendDynamicJump(branchAddress, lazy, BranchLogic.BranchType.RETURN); + ppc2ir.appendBranch(branchAddress, lazy, BranchLogic.BranchType.RETURN); // stop translation on branch always if (BO == 0x14) { @@ -4672,7 +4672,7 @@ } OPT_RegisterOperand branchAddress = ppc2ir.getCTRRegister(); - ppc2ir.appendDynamicJump(branchAddress, lazy, BranchType.INDIRECT_BRANCH); + ppc2ir.appendBranch(branchAddress, lazy, BranchType.INDIRECT_BRANCH); // stop translation on branch always @@ -11705,7 +11705,7 @@ if ((LK == 0) || ppc2ir.traceContinuesAfterBranchAndLink(pc)) { // Plant branch block - ppc2ir.appendGoto(target_address, lazy, LK != 0 ? BranchType.CALL : BranchType.DIRECT_BRANCH); + ppc2ir.appendBranch(target_address, lazy, LK != 0 ? BranchType.CALL : BranchType.DIRECT_BRANCH); // stop translation on branch always if (BO == 0x14) { @@ -11724,14 +11724,14 @@ ppc2ir.setCurrentBlock(instructionEndBlock); ppc2ir.setNextBlock(ppc2ir.createBlockAfterCurrent()); - ppc2ir.appendGoto(pc + 4, lazy, BranchType.DIRECT_BRANCH); + ppc2ir.appendBranch(pc + 4, lazy, BranchType.DIRECT_BRANCH); return target_address; } } } else { // This was a branch and link and the trace should stop, so end // gracefully - ppc2ir.appendGoto(target_address, lazy, BranchType.CALL); + ppc2ir.appendBranch(target_address, lazy, BranchType.CALL); return -1; } } @@ -11804,7 +11804,7 @@ if (ppc2ir.traceContinuesAfterBranchAndLink(pc)) { return target_addr; } else { - ppc2ir.setReturnValueResolveLazinessAndBranchToFinish( + ppc2ir.appendTraceExit( (PPC_Laziness) lazy.clone(), new OPT_IntConstantOperand(target_addr)); return -1; Modified: src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/ppc/os/process/PPC_ProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) @@ -20,6 +20,7 @@ import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_OptimizingCompilerException; +import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.jikesrvm.compilers.opt.ir.OPT_HIRGenerator; import org.jikesrvm.ppc.PPC_Disassembler; @@ -139,8 +140,8 @@ * the generation context for the HIR generation * @return a HIR generator */ - public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { - return new PPC2IR(context); + public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context, DBT_Trace trace) { + return new PPC2IR(context, trace); } /** Modified: src/org/binarytranslator/arch/x86/decoder/X862IR.java =================================================================== --- src/org/binarytranslator/arch/x86/decoder/X862IR.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/x86/decoder/X862IR.java 2007-05-18 17:13:21 UTC (rev 123) @@ -16,6 +16,7 @@ import org.binarytranslator.generic.decoder.AbstractCodeTranslator; import org.binarytranslator.generic.decoder.Laziness; import org.binarytranslator.vmInterface.DBT_OptimizingCompilerException; +import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.classloader.VM_Atom; import org.jikesrvm.classloader.VM_BootstrapClassLoader; import org.jikesrvm.classloader.VM_FieldReference; @@ -100,8 +101,8 @@ /** * Constructor */ - public X862IR(OPT_GenerationContext context) { - super(context); + public X862IR(OPT_GenerationContext context, DBT_Trace trace) { + super(context, trace); // Create the registers SegReg = new OPT_Register[6]; @@ -147,7 +148,7 @@ appendInstruction(Binary.create(INT_ADD, esp, esp.copyRO(), new OPT_IntConstantOperand(4))); // Branch - setReturnValueResolveLazinessAndBranchToFinish((X86_Laziness) lazy.clone(), temp.copyRO()); + appendTraceExit((X86_Laziness) lazy.clone(), temp.copyRO()); return -1; } Modified: src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java 2007-05-18 17:13:21 UTC (rev 123) @@ -3649,7 +3649,7 @@ stack.writeValue(translationHelper, lazy, temp.copyRO()); // Branch - translationHelper.appendDynamicJump(destOp.copyRO(), lazy, BranchType.CALL); + translationHelper.appendBranch(destOp.copyRO(), lazy, BranchType.CALL); return -1; } @@ -3770,7 +3770,7 @@ translationHelper.appendInstruction(Binary.create(INT_ADD, esp, esp.copyRO(), new OPT_IntConstantOperand(4 + immediate))); // Branch - translationHelper.setReturnValueResolveLazinessAndBranchToFinish( + translationHelper.appendTraceExit( (X86_Laziness) lazy.clone(), temp.copyRO()); return -1; } @@ -4035,7 +4035,7 @@ translationHelper.appendInstruction(gotoInstr); translationHelper.setCurrentBlock(executeBranch); - translationHelper.appendGoto(target_address, lazy, BranchType.DIRECT_BRANCH); + translationHelper.appendBranch(target_address, lazy, BranchType.DIRECT_BRANCH); translationHelper.setCurrentBlock(fallThrough); return pc + length; @@ -4169,7 +4169,7 @@ if (modrm == null) { target_address = absolute ? immediate : pc + length + immediate; translationHelper.getCurrentBlock().deleteNormalOut(); - translationHelper.appendGoto(target_address, lazy, BranchType.DIRECT_BRANCH); + translationHelper.appendBranch(target_address, lazy, BranchType.DIRECT_BRANCH); } else { int operandSize; if (prefix3 == null) { @@ -4210,7 +4210,7 @@ * ppc2ir.setCurrentBlock(fallThrough); * ppc2ir.plantRecordUncaughtBcctr(pc, branchAddress.copyRO()); */ - translationHelper.setReturnValueResolveLazinessAndBranchToFinish( + translationHelper.appendTraceExit( (X86_Laziness) lazy.clone(), branchAddress.copyRO()); } return -1; Modified: src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) @@ -19,7 +19,6 @@ import org.binarytranslator.generic.memory.ByteAddressedMemory; import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.BadInstructionException; -import org.binarytranslator.arch.ppc.decoder.PPC_InstructionDecoder; import org.binarytranslator.arch.x86.os.process.linux.X86_LinuxProcessSpace; import org.binarytranslator.arch.x86.decoder.X862IR; import org.binarytranslator.arch.x86.decoder.X86_InstructionDecoder; @@ -150,8 +149,8 @@ * @param context the generation context for the HIR generation * @return a HIR generator */ - public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context) { - return new X862IR(context); + public OPT_HIRGenerator createHIRGenerator(OPT_GenerationContext context, DBT_Trace trace) { + return new X862IR(context, trace); } /** Modified: src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java 2007-05-18 17:13:21 UTC (rev 123) @@ -21,6 +21,7 @@ import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.classloader.VM_Atom; +import org.jikesrvm.classloader.VM_BytecodeConstants; import org.jikesrvm.classloader.VM_Class; import org.jikesrvm.classloader.VM_MemberReference; import org.jikesrvm.classloader.VM_Method; @@ -75,30 +76,22 @@ */ public abstract class AbstractCodeTranslator implements OPT_Constants, OPT_Operators { - /** - * VM_TypeReference of org.binarytranslator.generic.os.process.ProcessSpace - */ + /** The trace that we're currently translating code for. */ + protected final DBT_Trace trace; + + /** VM_TypeReference of org.binarytranslator.generic.os.process.ProcessSpace */ private static final VM_TypeReference psTref; - /** - * Method ProcessSpace.doSysCall - */ + /** Method ProcessSpace.doSysCall */ public static final VM_Method sysCallMethod; - /** - * VM_TypeReference of - * org.binarytranslator.generic.fault.BadInstructionException - */ + /** VM_TypeReference of org.binarytranslator.generic.fault.BadInstructionException */ public static final VM_Class badInstrKlass; - /** - * Method BadInstructionException.<init> - */ + /** Method BadInstructionException.<init> */ public static final VM_Method badInstrKlassInitMethod; - /** - * Method ProcessSpace.recordUncaughtBranchBadInstructionException.<init> - */ + /** Method ProcessSpace.recordUncaughtBranchBadInstructionException.<init> */ public static final VM_Method recordUncaughtBranchMethod; static { @@ -165,20 +158,25 @@ public final OPT_Instruction instruction; public final Laziness lazyStateAtJump; public final int pc; + public final BranchType type; - public UnresolvedJumpInstruction(OPT_Instruction instruction, Laziness lazyStateAtJump, int pc) { + public UnresolvedJumpInstruction(OPT_Instruction instruction, Laziness lazyStateAtJump, int pc, BranchType type) { this.instruction = instruction; this.lazyStateAtJump = lazyStateAtJump; this.pc = pc; + this.type = type; } } - /** List of unresolved Goto instructions */ - private final ArrayList<UnresolvedJumpInstruction> unresolvedGoto; - + /** + * List of unresolved direct branches. The destinations of direct branches are already known at + * translation time.*/ + private final ArrayList<UnresolvedJumpInstruction> unresolvedDirectBranches; - /** List of unresolved dynamic jumps */ - private final ArrayList<UnresolvedJumpInstruction> unresolvedDynamicJumps; + /** + * List of unresolved dynamic branches. Dynamics branches have a destination address that is only + * determined at runtime. */ + private final ArrayList<UnresolvedJumpInstruction> unresolvedDynamicBranches; /** * Constructor @@ -186,7 +184,11 @@ * @param context * The JRVM generation context for this trace. */ - protected AbstractCodeTranslator(OPT_GenerationContext context) { + protected AbstractCodeTranslator(OPT_GenerationContext context, DBT_Trace trace) { + + //Store the trace that we're invoked from + this.trace = trace; + // Make copies of popular variables gc = context; ps = ((DBT_Trace) (gc.method)).ps; @@ -202,14 +204,12 @@ // Create preFillBlock, currentBlock and finishBlock gc.prologue.insertOut(gc.epilogue); preFillBlock = createBlockAfter(gc.prologue); - currentBlock = createBlockAfter(preFillBlock); - finishBlock = createBlockAfterCurrent(); // Fix up stores - unresolvedGoto = new ArrayList<UnresolvedJumpInstruction>(); - unresolvedDynamicJumps = new ArrayList<UnresolvedJumpInstruction>(); + unresolvedDirectBranches = new ArrayList<UnresolvedJumpInstruction>(); + unresolvedDynamicBranches = new ArrayList<UnresolvedJumpInstruction>(); } /** Returns the number of previously translated instructions within this trace. */ @@ -227,27 +227,19 @@ // Translating the subtrace finished so resolve any unresolved // branches - do { - if (DBT_Options.resolveProceduresBeforeBranches) { - resolveAllDynamicJumpTargets(); - } - if (DBT_Options.resolveBranchesAtOnce) { - do { - resolveGoto(); - - } while (unresolvedGoto.size() != 0); - } else { - resolveGoto(); - - } - if (!DBT_Options.resolveProceduresBeforeBranches) { - resolveAllDynamicJumpTargets(); - } - } while (((unresolvedGoto.size() == 0) - && areDynamicJumpsReadyToResolve()) == false); + if (!DBT_Options.resolveDirectBranchesFirst) { + resolveAllDynamicBranchTargets(); + } + //Resolve all open direct first + resolveAllDirectBranches(); + + if (DBT_Options.resolveDirectBranchesFirst) { + resolveAllDynamicBranchTargets(); + } + // Resolve unresolved dynamic jumps - resolveDynamicJumps(); + resolveDynamicBranches(); // Finish up the trace finishTrace(); @@ -265,13 +257,13 @@ */ private void translateSubTrace(Laziness lazy, int pc) { currentPC = pc; - if (suitableToStop()) { + if (shallTraceStop()) { // Record mapping of this pc value and laziness to this block registerMapping(pc, lazy, currentBlock); // Create next block nextBlock = createBlockAfterCurrent(); // Finish block to return and exit - setReturnValueResolveLazinessAndBranchToFinish(lazy, + appendTraceExit(lazy, new OPT_IntConstantOperand(pc)); // Move currentBlock along currentBlock = nextBlock; @@ -279,6 +271,7 @@ do { if (DBT.VerifyAssertions) DBT._assert(currentBlock.getNumberOfRealInstructions() == 0); + // Record mapping of this pc value and laziness to this block registerMapping(pc, lazy, currentBlock); @@ -292,14 +285,14 @@ // Move currentBlock along currentBlock = nextBlock; currentPC = pc; + if (DBT.VerifyAssertions) DBT._assert(currentBlock.getNumberOfRealInstructions() == 0); // Are we translating in single instruction mode if (DBT_Options.singleInstrTranslation == true) { if (pc != -1) { - setReturnValueResolveLazinessAndBranchToFinish(lazy, - new OPT_IntConstantOperand(pc)); + appendTraceExit(lazy, new OPT_IntConstantOperand(pc)); } break; @@ -377,16 +370,22 @@ gc.cfg.linkInCodeOrder(currentBlock, newBlock); gc.cfg.linkInCodeOrder(newBlock, nxtBlock); - if (DBT.VerifyAssertions) - DBT._assert(currentBlock.isOut(nxtBlock)); + /*if (DBT.VerifyAssertions) + DBT._assert(currentBlock.isOut(nxtBlock));*/ - currentBlock.deleteOut(nxtBlock); - currentBlock.insertOut(newBlock); - newBlock.insertOut(nxtBlock); + if (currentBlock.isOut(nxtBlock)) { + currentBlock.deleteOut(nxtBlock); + currentBlock.insertOut(newBlock); + newBlock.insertOut(nxtBlock); + } + else { + currentBlock.insertOut(newBlock); + } if (DBT_Options.debugCFG) { report(String.format("Created block (%s) after current (%s).", newBlock, currentBlock)); } + return newBlock; } @@ -527,88 +526,69 @@ * @param branchType * The type of branch that best describes this jump. */ - public void appendGoto(int targetPC, Laziness targetLaziness, BranchType branchType) { + public void appendBranch(int targetPC, Laziness targetLaziness, BranchType branchType) { - //see if we already compiled the target address - OPT_BasicBlock target = findMapping(targetPC, targetLaziness); + //Place a GOTO instruction at this point. However, this instruction + //serves more as a placeholder and might be mutated later on. + OPT_Instruction jump = Goto.create(GOTO, null); + appendInstruction(jump); + UnresolvedJumpInstruction unresolvedJump = new UnresolvedJumpInstruction(jump, (Laziness)targetLaziness.clone(), targetPC, branchType); + unresolvedDirectBranches.add(unresolvedJump); - //if yes, just jump directly to it - if (target != null) { + //Notify the branch profile about certain types of branches + switch (branchType) { + case CALL: + ps.branchInfo.registerCall(currentPC, targetPC); + return; - if (DBT_Options.debugBranchResolution) - System.out.println(String.format("Found precompiled mapping for pc 0x%x: %s", targetPC, target)); - - OPT_Instruction jump = Goto.create(GOTO, target.makeJumpTarget()); - getCurrentBlock().insertOut(target); - appendInstruction(jump); - } - else { - //otherwise, we have to decide whether to compile that address into the trace or to compile - //it as a separate trace. We use the branchType hint for that... - - switch (branchType) { - case CALL: - //exit the trace on a call - ps.branchInfo.registerCall(currentPC, targetPC); - setReturnValueResolveLazinessAndBranchToFinish(targetLaziness, new OPT_IntConstantOperand(targetPC)); - break; - - case RETURN: - //exit the trace - ps.branchInfo.registerReturn(currentPC, targetPC); - setReturnValueResolveLazinessAndBranchToFinish(targetLaziness, new OPT_IntConstantOperand(targetPC)); - break; + case RETURN: + ps.branchInfo.registerReturn(currentPC, targetPC); + return; - default: - //compile the jump directly into the trace. - OPT_Instruction jump = Goto.create(GOTO, null); - UnresolvedJumpInstruction unresolvedJump = new UnresolvedJumpInstruction(jump, (Laziness)targetLaziness.clone(), targetPC); - unresolvedGoto.add(unresolvedJump); - } + default: + return; } - - } - /** Resolve a single goto instruction */ - private void resolveGoto() { + /** Resolve all unresolved direct branch instructions. */ + private void resolveAllDirectBranches() { - if (unresolvedGoto.size() == 0) - return; + for (int i = 0; i < unresolvedDirectBranches.size(); i++) { - //Get the jump that we're supposed to resolve - UnresolvedJumpInstruction unresolvedInstr = unresolvedGoto.remove(unresolvedGoto.size() - 1); - int targetPc = unresolvedInstr.pc; - Laziness lazyStateAtJump = unresolvedInstr.lazyStateAtJump; - OPT_Instruction gotoInstr = unresolvedInstr.instruction; - - if (DBT.VerifyAssertions) DBT._assert(Goto.conforms(gotoInstr)); - - OPT_BasicBlock targetBB = resolveJumpTarget(targetPc, lazyStateAtJump); - - if (DBT_Options.debugBranchResolution) { - report("Resolving goto " + lazyStateAtJump.makeKey(targetPc) + " " + targetBB); + //Get the jump that we're supposed to resolve + UnresolvedJumpInstruction unresolvedInstr = unresolvedDirectBranches.remove(unresolvedDirectBranches.size() - 1); + int targetPc = unresolvedInstr.pc; + Laziness lazyStateAtJump = unresolvedInstr.lazyStateAtJump; + OPT_Instruction gotoInstr = unresolvedInstr.instruction; + + if (DBT.VerifyAssertions) DBT._assert(Goto.conforms(gotoInstr)); + + OPT_BasicBlock targetBB = resolveBranchTarget(targetPc, lazyStateAtJump, unresolvedInstr.type); + + if (DBT_Options.debugBranchResolution) { + report("Resolving goto " + lazyStateAtJump.makeKey(targetPc) + " " + targetBB); + } + + // Fix up instruction + Goto.setTarget(gotoInstr, targetBB.makeJumpTarget()); + gotoInstr.getBasicBlock().insertOut(targetBB); + + if (DBT_Options.debugBranchResolution) { + report("Properly resolving goto in block " + + gotoInstr.getBasicBlock() + " to " + lazyStateAtJump.makeKey(targetPc) + " " + + targetBB); + } } - - // Fix up instruction - Goto.setTarget(gotoInstr, targetBB.makeJumpTarget()); - gotoInstr.getBasicBlock().insertOut(targetBB); - - if (DBT.VerifyAssertions) DBT._assert(gotoInstr.getBasicBlock().getNumberOfNormalOut() == 1); - - if (DBT_Options.debugBranchResolution) { - report("Properly resolving goto in block " - + gotoInstr.getBasicBlock() + " to " + lazyStateAtJump.makeKey(targetPc) + " " - + targetBB); - } } /** - * Resolves a jump target to an actual basic block. This method usually tries to compile the trace - * for any target addresses that have not yet been compiled. However, when - * {@link DBT_Options#singleInstrTranslation} is turned on, then this method will end the curren trace, - * just returning the address of the next instruction. + * Resolves a branch target to an actual basic block. In case the jump target is not yet part + * of this trace, this method also takes a decision about whether the target shall be translated + * into the trace. * + * Notice that, when {@link DBT_Options#singleInstrTranslation} is turned on, + * this method will always end the current trace, just returning the address of the next instruction. + * * @param targetPc * The address of the target basic block that. * @param lazyStateAtJump @@ -617,28 +597,42 @@ * A basic block that is equivalent to the program counter address <code>targetPc</code> in the * original binary. */ - private OPT_BasicBlock resolveJumpTarget(int targetPc, Laziness lazyStateAtJump) { + private OPT_BasicBlock resolveBranchTarget(int targetPc, Laziness lazyStateAtJump, BranchType branchtype) { //Resolve the address of the target block - OPT_BasicBlock targetBB; - if (DBT_Options.singleInstrTranslation == true) { - //In Single instruction mode, the target block just ends the trace + OPT_BasicBlock targetBB = findMapping(targetPc, lazyStateAtJump); + + //If the target is already part of this trace, then just use the precompiled target + if (targetBB != null) + return targetBB; + + /* The target Block is not yet translated. + * We do not want to translate it into the current trace if + * a) DBT_Options.singleInstrTranslation is enabled + * b) The jump target has already been compiled as a separate method within the code cache + * c) The trace is already too long + * d) the branch is supposedly a CALL or RETURN + */ + if (DBT_Options.singleInstrTranslation == true || + ps.codeCache.tryGet(targetPc) != null || + shallTraceStop() || + branchtype == BranchType.CALL || + branchtype == BranchType.RETURN) { + + //Just exit the trace and continue at the target address in a new trace if (currentBlock.getNumberOfRealInstructions() != 0) { currentBlock = createBlockAfterCurrentNotInCFG(); - System.out.println("Resolving branch to next block."); + + if (DBT_Options.debugBranchResolution) System.out.println("Resolving branch to next block."); } targetBB = currentBlock; - setReturnValueResolveLazinessAndBranchToFinish(lazyStateAtJump, new OPT_IntConstantOperand(targetPc)); - } + appendTraceExit(lazyStateAtJump, new OPT_IntConstantOperand(targetPc)); + registerMapping(targetPc, lazyStateAtJump, targetBB); + } else { - //Try to find if block has now been translated + //Otherwise we will translate the jump into the trace + translateSubTrace((Laziness) lazyStateAtJump.clone(), targetPc); targetBB = findMapping(targetPc, lazyStateAtJump); - - if (targetBB == null) { - // Block not translated so translate - translateSubTrace((Laziness) lazyStateAtJump.clone(), targetPc); - targetBB = findMapping(targetPc, lazyStateAtJump); - } } if (DBT.VerifyAssertions) DBT._assert(targetBB != null); @@ -647,26 +641,23 @@ } /** - * Resolves all dynamic jumps that have been added with - * {@link #appendDynamicJump(OPT_RegisterOperand, Laziness, BranchType)}. + * Resolves all dynamic branches that have been added with + * {@link #appendBranch(OPT_RegisterOperand, Laziness, BranchType)}. */ - private void resolveDynamicJumps() { + private void resolveDynamicBranches() { - for (int i = 0; i < unresolvedDynamicJumps.size(); i++) { + for (int i = 0; i < unresolvedDynamicBranches.size(); i++) { - UnresolvedJumpInstruction unresolvedSwitch = unresolvedDynamicJumps.get(i); - - Laziness lazy = unresolvedSwitch.lazyStateAtJump; - OPT_Instruction lookupswitch = unresolvedSwitch.instruction; + UnresolvedJumpInstruction unresolvedSwitch = unresolvedDynamicBranches.get(i); Set<Integer> branchDests = getLikelyJumpTargets(unresolvedSwitch.pc); - resolveSingleDynamicJump(lazy, lookupswitch, branchDests); + resolveSingleDynamicJump(unresolvedSwitch, branchDests); } } /** * Resolves a single dynamic jump that has previously been created with - * {@link #appendDynamicJump(OPT_RegisterOperand, Laziness, BranchType)}. + * {@link #appendBranch(OPT_RegisterOperand, Laziness, BranchType)}. * * @param lazy * The lazy state of the jump that is to be resolved. @@ -675,7 +666,11 @@ * @param destinations * A list of known destinations that this dynamic jumps branches to. */ - private void resolveSingleDynamicJump(Laziness lazy, OPT_Instruction lookupswitch, Set<Integer> destinations) throws Error { + private void resolveSingleDynamicJump(UnresolvedJumpInstruction unresolvedJump, Set<Integer> destinations) throws Error { + + if (DBT.VerifyAssertions) DBT._assert(LookupSwitch.conforms(unresolvedJump.instruction)); + + OPT_Instruction lookupswitch = unresolvedJump.instruction; OPT_BranchOperand default_target = LookupSwitch.getDefault(lookupswitch); OPT_Operand value = LookupSwitch.getValue(lookupswitch); @@ -691,28 +686,19 @@ int match_no = 0; for (int dest_pc : destinations) { - OPT_BasicBlock target = findMapping(dest_pc, lazy); - if (target == null) { - throw new Error("Failed to find trace for " + dest_pc - + " with laziness " + lazy); - } - LookupSwitch.setMatch(lookupswitch, match_no, - new OPT_IntConstantOperand(dest_pc)); - LookupSwitch.setTarget(lookupswitch, match_no, target - .makeJumpTarget()); - LookupSwitch.setBranchProfile(lookupswitch, match_no, - new OPT_BranchProfileOperand(branchProb)); + OPT_BasicBlock target = resolveBranchTarget(dest_pc, unresolvedJump.lazyStateAtJump, unresolvedJump.type); + + LookupSwitch.setMatch(lookupswitch, match_no, new OPT_IntConstantOperand(dest_pc)); + LookupSwitch.setTarget(lookupswitch, match_no, target .makeJumpTarget()); + LookupSwitch.setBranchProfile(lookupswitch, match_no, new OPT_BranchProfileOperand(branchProb)); lookupswitch.getBasicBlock().insertOut(target); match_no++; } } else { int dest_pc = destinations.iterator().next(); - OPT_BasicBlock target = findMapping(dest_pc, lazy); - if (target == null) { - throw new Error("Failed to find trace for " + dest_pc - + " with laziness " + lazy); - } + OPT_BasicBlock target = resolveBranchTarget(dest_pc, unresolvedJump.lazyStateAtJump, unresolvedJump.type); + IfCmp.mutate(lookupswitch, INT_IFCMP, null, value, new OPT_IntConstantOperand(dest_pc), OPT_ConditionOperand.EQUAL(), target.makeJumpTarget(), @@ -725,7 +711,6 @@ } } - /** * Append a dynamic jump (a jump whose target address is not known at translation time) to the * current basic block. @@ -737,100 +722,71 @@ * @param branchType * The type of jump. */ - public void appendDynamicJump(OPT_RegisterOperand targetAddress, Laziness lazyStateAtJump, BranchType branchType) { + public void appendBranch(OPT_RegisterOperand targetAddress, Laziness lazyStateAtJump, BranchType branchType) { OPT_BasicBlock fallThrough = createBlockAfterCurrent(); OPT_Instruction switchInstr; switchInstr = LookupSwitch.create(LOOKUPSWITCH, targetAddress, null, null, fallThrough.makeJumpTarget(), null, 0); appendInstruction(switchInstr); - UnresolvedJumpInstruction unresolvedInfo = new UnresolvedJumpInstruction(switchInstr, (Laziness)lazyStateAtJump.clone(), currentPC); - unresolvedDynamicJumps.add(unresolvedInfo); + UnresolvedJumpInstruction unresolvedInfo = new UnresolvedJumpInstruction(switchInstr, (Laziness)lazyStateAtJump.clone(), currentPC, branchType); + unresolvedDynamicBranches.add(unresolvedInfo); setCurrentBlock(fallThrough); appendRecordUncaughtBranch(currentPC, targetAddress.copyRO(), branchType); - setReturnValueResolveLazinessAndBranchToFinish((Laziness) lazyStateAtJump.clone(), targetAddress.copyRO()); + appendTraceExit((Laziness) lazyStateAtJump.clone(), targetAddress.copyRO()); } /** - * Checks if all dynamic jumps are ready to be resolved (because their target blocks have - * been resolved). - * - * @return - * True if all dynamic jumps can be resolved, false otherwise. - */ - private boolean areDynamicJumpsReadyToResolve() { - for (int i = 0; i < unresolvedDynamicJumps.size(); i++) { - - UnresolvedJumpInstruction unresolvedSwitch = unresolvedDynamicJumps.get(i); - Laziness lazy = unresolvedSwitch.lazyStateAtJump; - Set<Integer> branchDests = getLikelyJumpTargets(unresolvedSwitch.pc); - - if (branchDests != null) { - for (int dest_pc : branchDests) { - if (findMapping(dest_pc, lazy) == null) { - return false; - } - } - } - } - return true; - } - - /** * Resolves all dynamic jump targets by making sure the respective basic blocks exist. */ - private void resolveAllDynamicJumpTargets() { - for (int i = 0; i < unresolvedDynamicJumps.size(); i++) { + private void resolveAllDynamicBranchTargets() { + for (int i = 0; i < unresolvedDynamicBranches.size(); i++) { - UnresolvedJumpInstruction unresolvedSwitch = unresolvedDynamicJumps.get(i); + UnresolvedJumpInstruction unresolvedSwitch = unresolvedDynamicBranches.get(i); Laziness lazy = unresolvedSwitch.lazyStateAtJump; Set<Integer> branchDests = getLikelyJumpTargets(unresolvedSwitch.pc); + if (branchDests != null) { for (int dest_pc : branchDests) { - if (findMapping(dest_pc, lazy) == null) { - // Block not translated so translate - translateSubTrace((Laziness) lazy.clone(), dest_pc); - } + resolveBranchTarget(dest_pc, lazy, unresolvedSwitch.type); } } } } - - /** * Set the return value in the currentBlock, resolve its lazy state (so the * state is no longer lazy) and then set it to branch to the finish block * - * @param value + * @param nextPc * return value for translated code (the PC value of the next * instruction to translate) */ - public void setReturnValueResolveLazinessAndBranchToFinish(Laziness laziness, - OPT_Operand value) { + public void appendTraceExit(Laziness laziness, OPT_Operand nextPc) { - nextBlock = createBlockAfterCurrent(); + //nextBlock = createBlockAfterCurrentNotInCFG(); + // Copy the value into the register specified by gc.resultReg. - appendInstruction(Move.create(INT_MOVE, - new OPT_RegisterOperand(gc.resultReg, VM_TypeReference.Int), value)); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(gc.resultReg, VM_TypeReference.Int), nextPc)); resolveLaziness(laziness); - appendInstruction(Goto.create(GOTO, finishBlock - .makeJumpTarget())); + appendInstruction(Goto.create(GOTO, finishBlock.makeJumpTarget())); currentBlock.deleteNormalOut(); currentBlock.insertOut(finishBlock); if (DBT.VerifyAssertions) DBT._assert(currentBlock.getNumberOfNormalOut() == 1); - currentBlock = nextBlock; + + //currentBlock = nextBlock; } /** - * Is it suitable to stop the trace now? + * Should the trace be stopped as soon as possible? This function can be used to steer how large a single + * trace may be. Return true if the target size for the trace is about to be or has been exceeded. * * @return true => try to stop the trace */ - protected boolean suitableToStop() { + protected boolean shallTraceStop() { if (DBT_Options.singleInstrTranslation && (numberOfInstructions >= 1)) { return true; } else { @@ -880,7 +836,7 @@ * @return whether the trace should continue */ public boolean traceContinuesAfterBranchAndLink(int pc) { - return suitableToStop() == false; + return shallTraceStop() == false; } /** @@ -1015,7 +971,7 @@ appendInstruction(t); - setReturnValueResolveLazinessAndBranchToFinish(lazy, + appendTraceExit(lazy, new OPT_IntConstantOperand(0xEBADC0DE)); } @@ -1312,6 +1268,37 @@ while (block != null && count-- > 0); } + /** + * Appends an call instruction the current trace. + * + * @param callInstruction + * The call instruction that shall be added to the current block. + */ + public void appendCustomCall(OPT_Instruction callInstruction) { + if (DBT.VerifyAssertions) DBT._assert(Call.conforms(callInstruction)); + + OPT_MethodOperand methOp = Call.getMethod(callInstruction); + VM_MethodReference methodRef = methOp.getMemberRef().asMethodReference(); + int callType; + + if (methOp.isVirtual()) + callType = VM_BytecodeConstants.JBC_invokespecial; + else + if (methOp.isInterface()) + callType = VM_BytecodeConstants.JBC_invokeinterface; + else + if (methOp.isSpecial()) + callType = VM_BytecodeConstants.JBC_invokespecial; + else + throw new RuntimeException("Unknown call type in call to appendCustomCall()."); + + trace.registerDynamicLink(methodRef, callType); + + //append the instruction to the current block + callInstruction.position = gc.inlineSequence; + appendInstruction(callInstruction); + } + /** Report some debug output */ protected abstract void report(String str); Added: src/org/binarytranslator/generic/decoder/CodeCache.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeCache.java (rev 0) +++ src/org/binarytranslator/generic/decoder/CodeCache.java 2007-05-18 17:13:21 UTC (rev 123) @@ -0,0 +1,39 @@ +package org.binarytranslator.generic.decoder; + +import java.util.WeakHashMap; + +import org.binarytranslator.vmInterface.DBT_Trace; + +/** Caches traces and the PC - addresses that they start from. */ +public class CodeCache { + + /** Stores the cached traces. The address at which the trace starts is used as the key. */ + private WeakHashMap<Integer, DBT_Trace> codeSnippets = new WeakHashMap<Integer, DBT_Trace>(); + + /** + * Adds a trace to the codecache. + * @param pc + * The address at which the trace starts. + * @param trace + * The cached trace. + */ + public void add(int pc, DBT_Trace trace) { + + if (codeSnippets.containsKey(pc)) + throw new RuntimeException("The codecache already contains a translation for 0x" + Integer.toHexString(pc)); + + codeSnippets.put(pc, trace); + } + + /** + * Try to retrieve a cached version of a trace starting at <code>pc</code>. + * @param pc + * The address at which the sought trace starts. + * @return + * A trace that starts at <code>pc</code> or null if the cache does not contain + * such a trace. + */ + public DBT_Trace tryGet(int pc) { + return codeSnippets.get(pc); + } +} Modified: src/org/binarytranslator/generic/execution/DynamicTranslationController.java =================================================================== --- src/org/binarytranslator/generic/execution/DynamicTranslationController.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/generic/execution/DynamicTranslationController.java 2007-05-18 17:13:21 UTC (rev 123) @@ -1,7 +1,5 @@ package org.binarytranslator.generic.execution; -import java.util.Hashtable; - import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.fault.BadInstructionException; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -16,13 +14,8 @@ */ public class DynamicTranslationController extends ExecutionController { - /** Caches pre-translated code and uses the starting address of the code on the subject machine as a key*/ - private final Hashtable<Integer, DBT_Trace> codeHash; - public DynamicTranslationController(ProcessSpace ps) { super(ps); - - codeHash = new Hashtable<Integer, DBT_Trace>(); } @Override @@ -51,7 +44,7 @@ * An executable VM_CodeArray, which contains a trace starting at the given address. */ private VM_CodeArray getCodeForPC(int pc) { - DBT_Trace trace = codeHash.get(pc); + DBT_Trace trace = ps.codeCache.tryGet(pc); if (trace == null) { trace = translateCode(pc); @@ -81,9 +74,9 @@ // compile the given trace trace.compile(); - // store the compiled code in code hash - codeHash.put(trace.pc, trace); - + // store the compiled code in the code cache + ps.codeCache.add(pc, trace); + return trace; } } Modified: src/org/binarytranslator/generic/memory/CallBasedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-05-17 22:26:48 UTC (rev 122) +++ src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-05-18 17:13:21 UTC (rev 123) @@ -9,6 +9,7 @@ package org.binarytranslator.generic.memory; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.decoder.AbstractCodeTranslator; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; @@ -118,39 +119,42 @@ */ protected CallBasedMemory(Class memoryClass) { //Debug initializations to run this stuff on SUN - /*memoryType = null; - loadS8 = loadU8 = loadS16 = loadU16 = load32 = null; - store8 = store16 = store32 = null;*/ - + if (DBT_Options.buildForSunVM) { + memoryType = null; + loadS8 = loadU8 = loadS16 = loadU16 = load32 = null; + store8 = store16 = store32 = null; + } + else { memoryType = VM_TypeReference.findOrCreate(memoryClass); - VM_Atom storeDescriptor = VM_Atom.findOrCreateAsciiAtom("(II)V"); - store8 = VM_MemberReference.findOrCreate(memoryType, - VM_Atom.findOrCreateAsciiAtom("store8"), storeDescriptor) - .asMethodReference().resolve(); - store16 = VM_MemberReference.findOrCreate(memoryType, - VM_Atom.findOrCreateAsciiAtom("store16"), storeDescriptor) - .asMethodReference().resolve(); - store32 = VM_MemberReference.findOrCreate(memoryType, - VM_Atom.findOrCreateAsciiAtom("store32"), storeDescriptor) - .asMethodReference().resolve(); + VM_Atom storeDescriptor = VM_Atom.findOrCreateAsciiAtom("(II)V"); + store8 = VM_MemberReference.findOrCreate(memoryType, + VM_Atom.findOrCreateAsciiAtom("store8"), storeDescriptor) + .asMethodReference().resolve(); + store16 = VM_MemberReference.findOrCreate(memoryType, + VM_Atom.findOrCreateAsciiAtom("store16"), storeDescriptor) + .asMethodReference().resolve(); + store32 = VM_MemberReference.findOrCreate(memoryType, + VM_Atom.findOrCreateAsciiAtom("store32"), storeDescriptor) + .asMethodReference().resolve(); - VM_Atom loadDescriptor = VM_Atom.findOrCreateAsciiAtom("(I)I"); - loadS8 = VM_MemberReference.findOrCreate(mem... [truncated message content] |
From: <mic...@us...> - 2007-05-19 15:20:18
|
Revision: 124 http://svn.sourceforge.net/pearcolator/?rev=124&view=rev Author: michael_baer Date: 2007-05-19 08:20:17 -0700 (Sat, 19 May 2007) Log Message: ----------- - Introduced a working version of dynamic linking for ARM Modified Paths: -------------- src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java src/org/binarytranslator/generic/os/loader/Loader.java src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java src/org/binarytranslator/generic/os/loader/image/ImageLoader.java src/org/binarytranslator/generic/os/process/ProcessSpace.java Added Paths: ----------- src/org/binarytranslator/arch/arm/os/process/loader/ src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java Removed Paths: ------------- src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/Main.java 2007-05-19 15:20:17 UTC (rev 124) @@ -89,8 +89,13 @@ ps = loader.readBinary(DBT_Options.executableFile); } catch (java.io.IOException e) { - throw new Error("Error accessing file: " + args[0], e); + System.err.println("Error accesing file: " + args[0] + ". " + e.getMessage()); + return; } + catch (Error e) { + System.err.println(e.getMessage()); + return; + } report("Sucessfully created process."); Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-05-19 15:20:17 UTC (rev 124) @@ -79,8 +79,8 @@ } @Override - public void initialise(Loader loader, int pc, int brk) { - registers.set(ARM_Registers.PC, pc); + public void initialise(Loader loader) { + registers.set(ARM_Registers.PC, loader.getEntryPoint()); } } Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-05-19 15:20:17 UTC (rev 124) @@ -46,9 +46,9 @@ } @Override - public void initialise(Loader loader, int pc, int brk) { - registers.set(ARM_Registers.PC, pc); - sysCalls.initialize(brk); + public void initialise(Loader loader) { + registers.set(ARM_Registers.PC, loader.getEntryPoint()); + sysCalls.initialize(loader.getBrk()); // initialize the stack auxVector = new int[] { Added: src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java (rev 0) +++ src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java 2007-05-19 15:20:17 UTC (rev 124) @@ -0,0 +1,139 @@ +package org.binarytranslator.arch.arm.os.process.loader; + +import java.io.IOException; + +import org.binarytranslator.DBT; +import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; +import org.binarytranslator.arch.arm.os.process.ARM_Registers; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.loader.elf.ELF_File; +import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.JavaRuntimeLinker; +import org.binarytranslator.generic.os.loader.elf.ELF_File.RelocationTable; +import org.binarytranslator.generic.os.loader.elf.ELF_File.StringTable; +import org.binarytranslator.generic.os.loader.elf.ELF_File.SymbolTable; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public class ARM_RuntimeLinker extends JavaRuntimeLinker { + + /** Introduce symbolic names for the different ARM relocation types. */ + private final static int R_ARM_ABS32 = 2; + private final static int R_ARM_GLOB_DAT = 21; + private final static int R_ARM_JUMP_SLOT = 22; + private final static int R_ARM_RELATIVE = 23; + + public ARM_RuntimeLinker(ProcessSpace ps, ELF_Loader loader) { + super(ps, loader); + + //TODO: Introduce some kind of class for ELF library managements + String libDir = "C:\\0Dateien\\University of Manchester\\MSc Thesis\\ARM Executables\\Dynamically Linked\\Hello World\\"; + libNames.put("libc.so.6", libDir + "libc-2.2.5.so"); + libNames.put("ld-linux.so.2", libDir + "ld-linux.so.2"); + } + + @Override + protected void relocate(SharedObject lib, ELF_File.RelocationTable reloc) throws IOException { + + if (reloc.hasAddends) + throw new Error("ARM should not encounter RELA sections when runtime linking executable files."); + + //get the symbol table for this library + SymbolTable symtab = lib.getDynamicSection().findSymbolTable(); + + //get the library's string table + StringTable strTab = lib.getDynamicSection().findStringTable(); + + //now start processing the library's relocation entries + for (RelocationTable.Entry entry : reloc.entries) { + + //where shall we store the resolved symbol + int resolveToAddress = entry.offset + lib.getLoadOffset(); + + switch (entry.relocationType) { + case R_ARM_ABS32: + { + SymbolTable.Entry symbol = symtab.getEntry(entry.symbolIndex); + + if (DBT.VerifyAssertions) DBT._assert(!symbol.isUndefined()); + + //this a local symbol that we can easily resolve + int offset = ps.memory.load32(resolveToAddress); + ps.memory.store32(resolveToAddress, symbol.value + lib.getLoadOffset() + offset); + } + break; + + case R_ARM_GLOB_DAT: + case R_ARM_JUMP_SLOT: + { + SymbolTable.Entry symbol = symtab.getEntry(entry.symbolIndex); + int value; + + if (symbol.isUndefined()) { + String symbolName = strTab.lookup(symbol.nameIdx); + value = resolveSymbolAddress(symbolName); + + if (value == -1) { + //we allow only weak symbols to be unresolved + if (symbol.binding != SymbolTable.STB_WEAK) { + throw new RuntimeException("Unable to resolve: " + symbolName + " in " + lib); + } + + continue; + } + } + else { + //this a local symbol that is already resolved. Just relocate it + value = symbol.value + lib.getLoadOffset(); + } + + //store the resolved symbol + ps.memory.store32(resolveToAddress, value); + } + break; + + case R_ARM_RELATIVE: + { + //R_ARM_RELATIVE + int address = ps.memory.load32(resolveToAddress); + ps.memory.store32(resolveToAddress, address + lib.getLoadOffset()); + } + break; + + default: + throw new RuntimeException("Unknown relocation type: " + entry.relocationType); + } + } + } + + @Override + protected void runInitRoutine(int startPC) { + + int pc = startPC; + ps.setCurrentInstructionAddress(startPC); + + Interpreter interpreter = ps.createInstructionInterpreter(); + + ((ARM_ProcessSpace)ps).registers.set(ARM_Registers.LR, startPC); + + while (!ps.finished) { + + Interpreter.Instruction instruction = interpreter.decode(pc); + instruction.execute(); + pc = instruction.getSuccessor(pc); + + if (pc == -1) + pc = ps.getCurrentInstructionAddress(); + else + ps.setCurrentInstructionAddress(pc); + + //we're done running the init method + if (pc == startPC) + break; + } + + if (ps.finished) { + throw new RuntimeException("ProcessSpace exited while running the INIT routine of a dynamically linked library."); + } + } + +} Modified: src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/arch/ppc/os/process/linux/PPC_LinuxProcessSpace.java 2007-05-19 15:20:17 UTC (rev 124) @@ -60,17 +60,12 @@ /** * Initialise the process space, called after the binary has been loaded * - * @param pc - * the entry point - * @param brk - * the initial value for the top of BSS - * @param args - * command line arguments */ - public void initialise(Loader loader, int pc, int brk) { - this.pc = pc; + @Override + public void initialise(Loader loader) { + this.pc = loader.getEntryPoint(); this.r1 = initialiseStack(loader, pc); - syscalls.initialize(brk); + syscalls.initialize(loader.getBrk()); } /** Modified: src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/arch/x86/os/process/linux/X86_LinuxProcessSpace.java 2007-05-19 15:20:17 UTC (rev 124) @@ -64,10 +64,11 @@ * @param brk the initial value for the top of BSS * @param args command line arguments */ - public void initialise(Loader loader, int pc, int brk) { - registers.eip = pc; + @Override + public void initialise(Loader loader) { + registers.eip = loader.getEntryPoint(); - registers.writeGP32(X86_Registers.ESP, initialiseStack(loader, pc)); + registers.writeGP32(X86_Registers.ESP, initialiseStack(loader)); if (useSysInfoPage) { try { memory.map(0xffffe000, 8192, true, true, true); @@ -79,13 +80,14 @@ memory.store8(0xffffe400, 0xC3); // RET } - syscalls.initialize(brk); + syscalls.initialize(loader.getBrk()); } /** * Initialise the stack */ - private int initialiseStack(Loader loader, int pc) { + private int initialiseStack(Loader loader) { + auxVector = new int[] { LinuxStackInitializer.AuxiliaryVectorType.AT_HWCAP, 0x078bfbff, LinuxStackInitializer.AuxiliaryVectorType.AT_PAGESZ, 0x1000, @@ -94,7 +96,7 @@ LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, ((ELF_Loader)loader).getNumberOfProgramSegmentHeaders(), LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x0, LinuxStackInitializer.AuxiliaryVectorType.AT_FLAGS, 0x0, - LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, pc, + LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, loader.getEntryPoint(), LinuxStackInitializer.AuxiliaryVectorType.AT_UID, DBT_Options.UID, LinuxStackInitializer.AuxiliaryVectorType.AT_EUID, DBT_Options.UID, Modified: src/org/binarytranslator/generic/os/loader/Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/Loader.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/loader/Loader.java 2007-05-19 15:20:17 UTC (rev 124) @@ -33,11 +33,6 @@ System.out.println(s); } } - - /* - * Abstract methods defined by the relavent binary loader - */ - /** * Create a process space, load the binary into it and initialise the stack, * etc. @@ -69,6 +64,12 @@ /** Shall return the Application Binary Interface that is required to load this executable. */ public abstract ABI getABI(); + + /** Shall return the top of the stack. */ + public abstract int getBrk(); + + /** Shall return the address at which execution of the program starts. */ + public abstract int getEntryPoint(); /** * Open and read the start of the file to determine the appropriate file Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-05-19 15:20:17 UTC (rev 124) @@ -23,14 +23,10 @@ public class ELF_File { - /** - * Wrapper class used for reading the ELF file with the required endianness - */ + /** Wrapper class used for reading the ELF file with the required endianness */ private BinaryReader reader; - /** - * Header of ELF file - */ + /** Header of ELF file */ private Header header; /** @@ -835,7 +831,7 @@ this.sectionIndex = sectionIndex; } - final boolean isUndefined() { + public final boolean isUndefined() { return sectionIndex == SHN_UNDEF; } } @@ -1112,9 +1108,9 @@ if (tabLocation == null || tabSize == null || entrySize == null | entryType == null) return null; - relaTab = new RelocationTable(tabLocation.value, tabSize.value, entrySize.value, entryType.value == DT_RELA); + RelocationTable jmpRel= new RelocationTable(tabLocation.value, tabSize.value, entrySize.value, entryType.value == DT_RELA); - return relaTab; + return jmpRel; } public RelocationTable findRelaTable() throws IOException { Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-05-19 15:20:17 UTC (rev 124) @@ -2,18 +2,30 @@ import java.io.IOException; -import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; -import org.binarytranslator.arch.arm.os.process.ARM_Registers; -import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; -import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.loader.Loader; -import org.binarytranslator.generic.os.loader.elf.ELF_File.DynamicSection; import org.binarytranslator.generic.os.process.ProcessSpace; public class ELF_Loader extends Loader { + /** The file that we're trying to load. */ private ELF_File file; - private ELF_File loader; + + /** The top of the stack segment. */ + private int brk; + + /** The entry point at which execution of the program starts. */ + private int entryPoint; + + @Override + public int getEntryPoint() { + return entryPoint; + } + + @Override + public int getBrk() { + return brk; + } @Override public ABI getABI() { @@ -25,18 +37,34 @@ return file.getHeader().getISA(); } + /** Returns the file that we're trying to load. */ + public ELF_File getFile() { + return file; + } + + /** Returns the address at which the executable's program header has been mapped into memory. */ public int getProgramHeaderAddress() { return file.getProgramHeaderAddress(); } + /** Returns the number of program headers within the executable. */ public int getNumberOfProgramSegmentHeaders() { return file.getHeader().getNumberOfProgramSegmentHeaders(); } - + + /** Returns the size of a single program header within memory. */ public int getProgramSegmentHeaderSize() { return file.getHeader().getProgramSegmentHeaderSize(); } + /** + * Checks if the given file is in ELF format. + * + * @param filename + * The name of the file that is to be checked. + * @return + * True if the file is an ELF file, false otherwise. + */ public static boolean conforms(String filename) { return ELF_File.conforms(filename); } @@ -48,62 +76,41 @@ ProcessSpace ps = ProcessSpace.createProcessSpaceFromBinary(this); ELF_File.SegmentHeader[] segments = file.getProgramSegmentHeaders(); - - System.out.println("ELF has segments:"); - for (ELF_File.SegmentHeader header : segments) { - System.out.println(header.toString()); - header.create(ps); + + if (DBT_Options.debugLoader) { + System.out.println("ELF has segments:"); + + for (ELF_File.SegmentHeader segment : segments) { + System.out.println(" - " + segment.toString()); + } } - int brk; - if (segments.length > 1) - brk = segments[1].getEnd(); - else - brk = segments[0].getEnd(); + //Determine the top of the stack. + //NB: I just copied that code from the old ELF loader. Is this really correct? + brk = segments[segments.length > 1 ? 1 : 0].getEnd(); - if (file.getDynamicSection() != null && file.getHeader().getABI() == ABI.ARM) { + //determine the entry point to the program + entryPoint = file.getHeader().getEntryPoint(); + + if (file.getDynamicSection() != null) { + + if (DBT_Options.debugLoader) System.out.println("Executable is dynamically linked."); - ARM_ProcessSpace armps = (ARM_ProcessSpace)ps; - - //invoke the runtime linker - RuntimeLinker ld = new RuntimeLinker(file, ps); + //This is a dynamically linked file, so hand over control to the runtime linker + RuntimeLinker ld = RuntimeLinker.create(ps, this); ld.link(); + } + else { + if (DBT_Options.debugLoader) System.out.println("Executable is statically linked."); - ps.initialise(this, file.getHeader().getEntryPoint(), brk); - int startInstruction = ps.getCurrentInstructionAddress(); - - //call the INITs - Interpreter interpreter = ps.createInstructionInterpreter(); - for (Integer init : ld.initMethods) { - int pc = init; - - ps.setCurrentInstructionAddress(init); - armps.registers.set(ARM_Registers.LR, init); - - while (!ps.finished) { - - Interpreter.Instruction instruction = interpreter.decode(pc); - System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); - - instruction.execute(); - pc = instruction.getSuccessor(pc); - - if (pc == -1) - pc = ps.getCurrentInstructionAddress(); - else - ps.setCurrentInstructionAddress(pc); - - //we're done running the init method - if (pc == init) - break; - } + //this is a statically linked file. We simply need to map all of its segments into memory + for (ELF_File.SegmentHeader segment : segments) { + segment.create(ps); } - ld._tmpRestore(); - ps.setCurrentInstructionAddress(startInstruction); + //and then initialize the process space + ps.initialise(this); } - else - ps.initialise(this, file.getHeader().getEntryPoint(), brk); return ps; } Copied: src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java (from rev 106, src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java) =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java (rev 0) +++ src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-05-19 15:20:17 UTC (rev 124) @@ -0,0 +1,412 @@ +package org.binarytranslator.generic.os.loader.elf; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.os.loader.elf.ELF_File.DynamicSection; +import org.binarytranslator.generic.os.loader.elf.ELF_File.SegmentHeader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.StringTable; +import org.binarytranslator.generic.os.loader.elf.ELF_File.SymbolTable; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public abstract class JavaRuntimeLinker extends RuntimeLinker { + + /** The process space that we're linking the file in. */ + protected final ProcessSpace ps; + + /** The loader that triggered the runtime linking. */ + private final ELF_Loader loader; + + /** the file that we're ultimately trying to link */ + private ELF_File file; + + /** A list of all libraries that are referenced within the loading process. */ + private LinkedList<SharedObject> libraries = new LinkedList<SharedObject>(); + + /** A list of the star addres of all init routines, that we're supposed to execute. */ + public LinkedList<Integer> initMethods = new LinkedList<Integer>(); + + /** The address of the memory block that is going to be allocated to the next library*/ + private int nextMemoryBlock = 1024*1024*1024; //start mapping libraries at 1GB (0x40000000) + + /** Maps a library name to a filename. */ + protected final HashMap<String, String> libNames = new HashMap<String, String>();; + + public static class SharedObject { + /** The libary's name. */ + private final String filename; + + /** The elf file that this library can be loaded from. */ + private ELF_File file = null; + + /** The dynamic section of this library */ + private ELF_File.DynamicSection dynamicSection = null; + + /** Is the library already relocated? */ + private boolean relocated = false; + + /** Stores if a library can only be loaded at a specific load offset. This is generally only true for the program file. */ + private final boolean hasFixedLoadOffset; + + /** The address at which this library has been loaded. */ + private int loadedAt; + + /** Other libraries, that this library depends upon. */ + private SharedObject[] dependencies = null; + + public SharedObject(String filename) { + this.filename = filename; + this.hasFixedLoadOffset = false; + } + + public SharedObject(String filename, int fixedLoadOffset) { + this.filename = filename; + this.loadedAt = fixedLoadOffset; + this.hasFixedLoadOffset = true; + } + + /** The elf file that this library can be loaded from. */ + public ELF_File getFile() throws IOException { + if (file == null) + file = new ELF_File(filename); + + return file; + } + + /** Returns the dynamic section of this library */ + public ELF_File.DynamicSection getDynamicSection() throws IOException { + if (dynamicSection == null) { + dynamicSection = getFile().getDynamicSection(); + } + + return dynamicSection; + } + + /** Returns the address at which this library has been loaded. */ + public int getLoadOffset() { + return loadedAt; + } + + /** Returns true if a libary can only be loaded at a fixed offset in memory. False otherwise. */ + public boolean hasFixedLoadOffset() { + return hasFixedLoadOffset; + } + + @Override + public String toString() { + File f = new File(filename); + return f.getName(); + } + } + + public JavaRuntimeLinker(ProcessSpace ps, ELF_Loader loader) { + this.ps = ps; + this.loader = loader; + this.file = loader.getFile(); + } + + /** + * This function is the main entry point into the dynamic linker and will steer the whole + * linking process. + */ + public final void link() throws IOException { + ELF_File.DynamicSection dynSection = file.getDynamicSection(); + + //align the library start address to a page + nextMemoryBlock = ps.memory.truncateToPage(nextMemoryBlock); + + if (dynSection == null) { + System.out.println("Unable to find dynamic linking segment."); + throw new UnsupportedOperationException("Trying to runtime-link a static executable."); + } + + //Create a representation for the program file, which is then treated like any other shared object + SharedObject programfile = new SharedObject("<Program File>", 0); + programfile.file = file; + libraries.add(programfile); + + //load the program file and all its dependend libraries + loadLibRecursively(programfile); + + //relocate all dynamic libraries + relocateLibRecursively(programfile); + + //Call the init routines that were registered by the different libraries + callInitRoutines(); + + //prepare to start the real program + ps.setCurrentInstructionAddress(loader.getEntryPoint()); + } + + /** + * Resolves a library, given by its <code>name</code> into a {@link SharedObject} object. + * If the library is referenced for the first time, it is added to the global list + * of available {@link #libraries}. + * + * @param name + * The name of the library that is to be resolved. + * @return + * A library object representing that library. + */ + private SharedObject resolveLibraryByName(String name) { + + String originalName = name; + name = libNames.get(name); + + if (name == null) + throw new RuntimeException("SharedObject not present: " + originalName); + + for (int i = 0; i < libraries.size(); i++) { + SharedObject lib = libraries.get(i); + + if (lib.filename.equals(name)) + return lib; + } + + SharedObject lib = new SharedObject(name); + libraries.addLast(lib); + return lib; + } + + /** + * Calls {@link #runInitRoutine(int)} several times to run all INIT routines for all loaded + * libraries. + */ + protected void callInitRoutines() throws IOException { + //the linker has a special symbol that determines if we're currently starting up + int dl_starting_up = resolveSymbolAddress("_dl_starting_up"); + + if (dl_starting_up != -1) + ps.memory.store32(dl_starting_up, 1); + + //Initialize the process space + ps.initialise(loader); + + //call the INIT functions + for (int init : initMethods) { + runInitRoutine(init); + } + + //note that we're done running the inits + if (dl_starting_up != -1) + ps.memory.store32(dl_starting_up, 0); + } + + /** + * Loads the library <code>lib</code> and all its dependencies into memory. + * All newly found dependencies (i.e. libraries that have to be loaded) are + * put into the global library collection. + * + * @param lib + * The library that is to be loaded. + */ + private void loadLibRecursively(SharedObject lib) throws IOException { + + //skip libraries, if their dependencies have already been resolved + if (lib.dependencies != null) + return; + + //get a few essential elements within the library (.dynamic section, string table etc.) + if (DBT_Options.debugLoader) System.out.println("Resolving dependencies for: " + lib); + DynamicSection libDynamicSection = lib.getDynamicSection(); + + if (libDynamicSection == null) + throw new RuntimeException("SharedObject " + lib + "is not a shared library."); + + StringTable libStrTab = libDynamicSection.findStringTable(); + + if (libStrTab == null) + throw new RuntimeException("Unable to find String table of shared library."); + + //resolve the library's dependencies + ELF_File.DynamicSection.Entry[] libDepends = libDynamicSection.getEntriesByType(ELF_File.DynamicSection.DT_NEEDED); + lib.dependencies = new SharedObject[libDepends.length]; + + //add all the libraries that this one depends on + for (int i = 0; i < libDepends.length; i++) { + String dependencyName = libStrTab.lookup(libDepends[i].value); + if (DBT_Options.debugLoader) System.out.println(" Depends on: " + dependencyName); + + //note the dependency + lib.dependencies[i] = resolveLibraryByName(dependencyName); + + //and also resolve their dependencies + loadLibRecursively(lib.dependencies[i]); + } + + //load the library to memory + loadSingleLibrary(lib); + } + + /** + * Relocate a library recursively by first relocating its dependencies and then + * relocating the library itself. + * + * @param lib + * The library that is to be relocated. + */ + private void relocateLibRecursively(SharedObject lib) throws IOException { + + //nothing to do if the library is already loaded + if (lib.relocated) { + return; + } + + //to avoid recursion due to circular dependencies, mark this library as loaded + lib.relocated = true; + + //load its dependencies + for (int i = 0; i < lib.dependencies.length; i++) + relocateLibRecursively(lib.dependencies[i]); + + //relocate the library itself + relocateSingleLib(lib); + + //Remember to execute it's INIT function later on + ELF_File.DynamicSection.Entry initMethod = lib.getDynamicSection().getEntryByType(ELF_File.DynamicSection.DT_INIT); + + if (initMethod != null) { + initMethods.add(initMethod.value + lib.loadedAt); + } + } + + /** + * Relocates a single library, but none of its dependencies. + * + * @param lib + * The library that is to be relocated. + */ + private void relocateSingleLib(SharedObject lib) throws IOException { + + DynamicSection libDynamicSection = lib.getDynamicSection(); + ELF_File.RelocationTable relTable = libDynamicSection.findRelTable(); + + if (DBT_Options.debugLoader) System.out.println("Performing relocation for: " + lib); + + if (relTable == null) { + if (DBT_Options.debugLoader) System.out.println(" No REL in " + lib); + } + else { + if (DBT_Options.debugLoader) System.out.println(" Performing REL in " + lib); + relocate(lib, relTable); + } + + relTable = libDynamicSection.findRelaTable(); + + if (relTable == null) { + if (DBT_Options.debugLoader) System.out.println(" No RELA in " + lib); + } + else { + if (DBT_Options.debugLoader) System.out.println(" Performing RELA in " + lib); + relocate(lib, relTable); + } + + relTable = libDynamicSection.findJmpRelTable(); + + if (relTable == null) { + if (DBT_Options.debugLoader) System.out.println(" No JMPREL in " + lib); + } + else { + if (DBT_Options.debugLoader) System.out.println(" Performing JMPREL in " + lib); + relocate(lib, relTable); + } + } + + /** + * Loads all segments belong to the library <code>lib</code> into memory. + * + * @param lib + * The library that shall be loaded to memory. + */ + private void loadSingleLibrary(SharedObject lib) { + + if (DBT.VerifyAssertions) DBT._assert(lib.loadedAt == 0); + + if (!lib.hasFixedLoadOffset()) { + // load the library to the next available address + lib.loadedAt = nextMemoryBlock; + } + + //do we need to write into the text segment? + boolean needRelocText = !lib.hasFixedLoadOffset() && lib.dynamicSection.getEntryByType(ELF_File.DynamicSection.DT_TEXTREL) != null; + + //start by mapping the library into memory + SegmentHeader segments[] = lib.file.getProgramSegmentHeaders(); + + //the highest offset from nextMemoryBlock that this shared object uses + long highestUsedAddress = 1; + + for (int i = 0; i < segments.length; i++) { + + //TODO: This is only a hack. We are making this segment writeable, because we need to relocate within it... + if (needRelocText) + segments[i].p_flags |= ELF_File.SegmentHeader.PF_W; + + //create the actual segment + segments[i].create(ps, lib.loadedAt); + + long thisAddress = segments[i].p_vaddr; + thisAddress += segments[i].p_memsz; + + if (thisAddress >= highestUsedAddress) + highestUsedAddress = thisAddress + 1; + } + + if (!lib.hasFixedLoadOffset()) { + //page-align the next memory block + nextMemoryBlock = ps.memory.truncateToNextPage((int)(highestUsedAddress + nextMemoryBlock + 5000)); + } + } + + /** + * Resolves the given <code>symbol</code> name into the address, to which the symbol + * has been relocated. + * + * @param symbol + * The name of the symbol that is to be resolved. + * @return + * The address of the symbol or -1, if the symbol's address could not be resolved. + */ + protected final int resolveSymbolAddress(String symbol) throws IOException { + Iterator<SharedObject> libs = libraries.iterator(); + + //iterate over the symbol table of every library that we already loaded + while (libs.hasNext()) { + SharedObject lib = libs.next(); + ELF_File.SymbolHashTable hashTab = lib.dynamicSection.findHashTable(); + + //see if <symbol> is defined within this library + SymbolTable.Entry entry = hashTab.lookup(symbol); + + if (entry != null && !entry.isUndefined()) + return entry.value + lib.loadedAt; + } + + return -1; + } + + /** + * This function is called as a request to run a libraries INIT routine. + * Implementations shall run the init routine, which is starting at address <code>startPC</code>. + * + * @param startPC + * The address at which the INIT routine is starting. + */ + protected abstract void runInitRoutine(int startPC); + + /** + * This function is called as a request to relocate the entries in <code>relocations</code> + * which belong to <code>library</code>. + * + * @param library + * The library that is to be relocated. + * @param relocations + * A table of relocation entries that are to be processed to relocate the library. + */ + protected abstract void relocate(SharedObject library, ELF_File.RelocationTable relocations) throws IOException; +} Deleted: src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/loader/elf/RuntimeLinker.java 2007-05-19 15:20:17 UTC (rev 124) @@ -1,434 +0,0 @@ -package org.binarytranslator.generic.os.loader.elf; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; - -import org.binarytranslator.DBT; -import org.binarytranslator.generic.os.loader.elf.ELF_File.RelocationTable; -import org.binarytranslator.generic.os.loader.elf.ELF_File.SegmentHeader; -import org.binarytranslator.generic.os.loader.elf.ELF_File.StringTable; -import org.binarytranslator.generic.os.loader.elf.ELF_File.SymbolTable; -import org.binarytranslator.generic.os.process.ProcessSpace; - -public class RuntimeLinker { - - /** */ - private final ProcessSpace ps; - - /** the file that we're ultimately trying to link */ - private ELF_File file; - - /** A list of all libraries that are referenced within the loading process. */ - private LinkedList<Library> libraries = new LinkedList<Library>(); - - /** A list of the star addres of all init routines, that we're supposed to execute. */ - public LinkedList<Integer> initMethods = new LinkedList<Integer>(); - - /** The address of the memory block that is going to be allocated to the next library*/ - private int nextMemoryBlock = 1024*1024*1024; //start mapping libraries at 1GB (0x40000000) - - /** Maps a library name to a filename. */ - private static HashMap<String, String> libNames; - - static { - String libDir = "C:\\0Dateien\\University of Manchester\\MSc Thesis\\ARM Executables\\Dynamically Linked\\Hello World\\"; - - libNames = new HashMap<String, String>(); - libNames.put("libc.so.6", libDir + "libc-2.2.5.so"); - libNames.put("ld-linux.so.2", libDir + "ld-linux.so.2"); - } - - private static class Library { - /** The libary's name. */ - public String filename; - - /** The elf file that this library can be loaded from. */ - public ELF_File file = null; - - /** The dynamic section of this library */ - public ELF_File.DynamicSection dynamicSection = null; - - /** Is the library already relocated? */ - public boolean relocated = false; - - /** The address at which this library has been loaded. */ - public int relocatedTo; - - /** Other libraries, that this library depends upon. */ - public Library[] dependencies = null; - - public Library(String filename) { - this.filename = filename; - } - - @Override - public String toString() { - File f = new File(filename); - return f.getName(); - } - } - - public RuntimeLinker(ELF_File file, ProcessSpace ps) { - this.file = file; - this.ps = ps; - } - - private Library addLibByName(String name) { - - String originalName = name; - name = libNames.get(name); - - if (name == null) - throw new RuntimeException("Library not present: " + originalName); - - for (int i = 0; i < libraries.size(); i++) { - Library lib = libraries.get(i); - - if (lib.filename.equals(name)) - return lib; - } - - Library lib = new Library(name); - libraries.addLast(lib); - return lib; - } - - public void link() throws IOException { - ELF_File.DynamicSection dynSection = file.getDynamicSection(); - - //align the library start address to a page - nextMemoryBlock = ps.memory.truncateToPage(nextMemoryBlock); - - if (dynSection == null) { - System.out.println("Unable to find dynamic linking segment."); - throw new UnsupportedOperationException("Trying to runtime-link a static executable."); - } - - System.out.println(dynSection); - - ELF_File.DynamicSection.Entry[] neededLibs = dynSection.getEntriesByType(ELF_File.DynamicSection.DT_NEEDED); - ELF_File.StringTable strTab = dynSection.findStringTable(); - - //grab the libraries that are needed by this executable - for (int i = 0; i < neededLibs.length; i++) { - String libName = strTab.lookup(neededLibs[i].value); - System.out.println("Needs lib: " + libName); - - Library lib = addLibByName(libName); - loadLibAndRecordDependencies(lib); - } - - //finally, link the remaining symbols from the executable - Library programfile = new Library("<Program File>"); - programfile.file = file; - programfile.dynamicSection = dynSection; - programfile.dependencies = new Library[0]; - libraries.add(programfile); - - //load the dynamic libraries - Iterator<Library> libs = libraries.listIterator(); - - while (libs.hasNext()) { - Library lib = libs.next(); - - if (!lib.relocated) - relocateLibRecursively(lib); - } - - System.out.println("Resolving undefined symbols in executable."); - - RelocationTable relTab = dynSection.findRelTable(); - if (relTab != null) { - System.out.println("Resolving REL in executable."); - relocate(programfile, relTab); - } - else - System.out.println("Could not find REL table in executable."); - - relTab = dynSection.findRelaTable(); - - if (relTab != null) { - System.out.println("Resolving RELA in executable."); - relocate(programfile, relTab); - } - else - System.out.println("Could not find RELA table in executable."); - - relTab = dynSection.findJmpRelTable(); - - if (relTab != null) { - System.out.println("Resolving JMPREL in executable."); - relocate(programfile, relTab); - } - else - System.out.println("Could not find JMPREL table in executable."); - - //Does the program file have a init method? If yes, call it later - ELF_File.DynamicSection.Entry initMethod = dynSection.getEntryByType(ELF_File.DynamicSection.DT_INIT); - - if (initMethod != null) { - initMethods.add(initMethod.value); - } - - - int symAddr = resolveSymbolAddress("_dl_starting_up"); - - DBT._assert(symAddr != -1); - ps.memory.store32(symAddr, 1); - - - } - - //TODO: Remove - public void _tmpRestore() throws IOException { - int symAddr = resolveSymbolAddress("_dl_starting_up"); - - DBT._assert(symAddr != -1); - ps.memory.store32(symAddr, 0); - } - - private void loadLibAndRecordDependencies(Library lib) throws IOException { - - //skip libraries, if their dependencies have already been resolved - if (lib.dependencies != null) - return; - - //get a few essential elements within the library (.dynamic section, string table etc.) - System.out.println("Resolving dependencies for: " + lib); - lib.file = new ELF_File(lib.filename); - lib.dynamicSection = lib.file.getDynamicSection(); - - if (lib.dynamicSection == null) - throw new RuntimeException("Library is not a shared library."); - - StringTable libStrTab = lib.dynamicSection.findStringTable(); - - if (libStrTab == null) - throw new RuntimeException("Unable to find String table of shared library."); - - //resolve the library's dependencies - ELF_File.DynamicSection.Entry[] libDepends = lib.dynamicSection.getEntriesByType(ELF_File.DynamicSection.DT_NEEDED); - lib.dependencies = new Library[libDepends.length]; - - - - //add all the libraries that this one depends on - for (int i = 0; i < libDepends.length; i++) { - String libName = libStrTab.lookup(libDepends[i].value); - System.out.println(" Depends on: " + libName); - - //note the dependency - lib.dependencies[i] = addLibByName(libName); - - //and also resolve their dependencies - loadLibAndRecordDependencies(lib.dependencies[i]); - } - - //load the library to memory - loadLibToMemory(lib); - - - } - - /** Load a library recursively by first loading its dependencies and then the library itself*/ - private void relocateLibRecursively(Library lib) throws IOException { - - //nothing to do if the library is already loaded - if (lib.relocated) { - return; - } - - //to avoid recursion due to circular dependencies, mark this library as loaded - lib.relocated = true; - - //load its dependencies - for (int i = 0; i < lib.dependencies.length; i++) - relocateLibRecursively(lib.dependencies[i]); - - //relocate the library itself - relocateSingleLib(lib); - - //Remember to execute it's INIT function later on - ELF_File.DynamicSection.Entry initMethod = lib.dynamicSection.getEntryByType(ELF_File.DynamicSection.DT_INIT); - - if (initMethod != null) { - initMethods.add(initMethod.value + lib.relocatedTo); - } - } - - /** Loads and relocates a single library (none of the dependencies). */ - private void relocateSingleLib(Library lib) throws IOException { - - ELF_File.RelocationTable relTable = lib.dynamicSection.findRelTable(); - - if (relTable == null) - System.out.println("Did not find a REL table in " + lib); - else { - System.out.println("Performing REL relocation in " + lib); - relocate(lib, relTable); - } - - relTable = lib.dynamicSection.findRelaTable(); - - if (relTable == null) - System.out.println("Did not find a RELA table in " + lib); - else { - System.out.println("Performing RELA relocation in " + lib); - relocate(lib, relTable); - } - - relTable = lib.dynamicSection.findJmpRelTable(); - - if (relTable == null) - System.out.println("Did not find a JMPREL table in " + lib); - else { - System.out.println("Performing JMPREL relocation in " + lib); - relocate(lib, relTable); - } - } - - private void loadLibToMemory(Library lib) { - - if (DBT.VerifyAssertions) DBT._assert(lib.relocatedTo == 0); - - //load the library to the next available address - lib.relocatedTo = nextMemoryBlock; - - //do we need to write into the text segment? - boolean needRelocText = lib.dynamicSection.getEntryByType(ELF_File.DynamicSection.DT_TEXTREL) != null; - - //start by mapping the library into memory - SegmentHeader segments[] = lib.file.getProgramSegmentHeaders(); - - //the highest offset from nextMemoryBlock that this shared object uses - long highestUsedAddress = 1; - - for (int i = 0; i < segments.length; i++) { - - //TODO: This is only a hack. We are making this segment writeable, because we need to relocate within it... - if (needRelocText) - segments[i].p_flags |= ELF_File.SegmentHeader.PF_W; - - //create the actual segment - segments[i].create(ps, lib.relocatedTo); - - long thisAddress = segments[i].p_vaddr; - thisAddress += segments[i].p_memsz; - - if (thisAddress >= highestUsedAddress) - highestUsedAddress = thisAddress + 1; - } - - //page-align the next memory block - nextMemoryBlock = ps.memory.truncateToNextPage((int)(highestUsedAddress + nextMemoryBlock + 5000)); - } - - private int resolveSymbolAddress(String symbol) throws IOException { - Iterator<Library> libs = libraries.iterator(); - - //iterate over the symbol table of every library that we already loaded - while (libs.hasNext()) { - Library lib = libs.next(); - ELF_File.SymbolHashTable hashTab = lib.dynamicSection.findHashTable(); - - //see if <symbol> is defined within this library - SymbolTable.Entry entry = hashTab.lookup(symbol); - - if (entry != null && !entry.isUndefined()) - return entry.value + lib.relocatedTo; - } - - return -1; - } - - private void relocate(Library lib, ELF_File.RelocationTable reloc) throws IOException { - - if (reloc.hasAddends) - throw new RuntimeException("Not yet implemented"); - - //get the symbol table for this library - SymbolTable symtab = lib.dynamicSection.findSymbolTable(); - - //get the library's string table - StringTable strTab = lib.dynamicSection.findStringTable(); - - //now start processing the library's relocation entries - for (RelocationTable.Entry entry : reloc.entries) { - //SegmentHeader segment = lib.file.virtualAddressToSegment(entry.offset); - //int offsetFromSegment = entry.offset - segment.p_vaddr; - //int addr = segment.p_paddr + offsetFromSegment; - int addr = entry.offset + lib.relocatedTo; - - switch (entry.relocationType) { - case 21: - { - //R_ARM_GLOB_DAT - SymbolTable.Entry symbol = symtab.getEntry(entry.symbolIndex); - String symbolName = strTab.lookup(symbol.nameIdx); - System.out.println(symbolName); - if (symbol.isUndefined()) { - - int symAddr = resolveSymbolAddress(symbolName); - - if (symAddr == -1) { - //we allow only weak symbols to be unresolved - if (symbol.binding != SymbolTable.STB_WEAK && symAddr == -1) { - throw new RuntimeException("Unable to resolve: " + symbolName + " in " + lib); - } - - continue; - } - - //store the resolved symbol - ps.memory.store32(entry.offset + lib.relocatedTo, symAddr); - } - else { - //this a local symbol that is already resolved - ps.memory.store32(entry.offset + lib.relocatedTo, symbol.value + lib.relocatedTo); - } - } - break; - - case 22: - { - //R_ARM_JUMP_SLOT - SymbolTable.Entry symbol = symtab.getEntry(entry.symbolIndex); - String symbolName = strTab.lookup(symbol.nameIdx); - System.out.println(symbolName); - if (symbol.isUndefined()) { - - int symAddr = resolveSymbolAddress(symbolName); - - //we allow only weak symbols to be unresolved - if (symbol.binding != SymbolTable.STB_WEAK && symAddr == -1) { - throw new RuntimeException("Unable to resolve: " + symbolName + " in " + lib); - } - - //store the resolved symbol - ps.memory.store32(entry.offset + lib.relocatedTo, symAddr); - } - else { - //this a local symbol that we can easily resolve - ps.memory.store32(entry.offset + lib.relocatedTo, symbol.value + lib.relocatedTo); - } - } - break; - case 23: - { - //R_ARM_RELATIVE - int address = ps.memory.load32(addr); - //System.out.println(address); - ps.memory.store32(addr, address + lib.relocatedTo); - } - break; - - - default: - break; - } - } - } -} Modified: src/org/binarytranslator/generic/os/loader/image/ImageLoader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/image/ImageLoader.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/loader/image/ImageLoader.java 2007-05-19 15:20:17 UTC (rev 124) @@ -99,7 +99,7 @@ return null; } - ps.initialise(this, 0, -1); + ps.initialise(this); return ps; } @@ -133,4 +133,14 @@ System.out.println(s); } } + + @Override + public int getBrk() { + return -1; + } + + @Override + public int getEntryPoint() { + return 0; + } } Modified: src/org/binarytranslator/generic/os/process/ProcessSpace.java =================================================================== --- src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-05-18 17:13:21 UTC (rev 123) +++ src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-05-19 15:20:17 UTC (rev 124) @@ -116,7 +116,7 @@ * @param brk * the initial value for the top of BSS */ - public abstract void initialise(Loader loader, int pc, int brk); + public abstract void initialise(Loader loader); /** * Constructor This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-06-08 14:03:25
|
Revision: 128 http://svn.sourceforge.net/pearcolator/?rev=128&view=rev Author: michael_baer Date: 2007-06-08 07:03:26 -0700 (Fri, 08 Jun 2007) Log Message: ----------- Fixed bugs in the ARM translator when not using "Single-instruction-translation". Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java src/org/binarytranslator/arch/x86/decoder/X862IR.java src/org/binarytranslator/arch/x86/decoder/X86_InstructionDecoder.java src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/memory/AutoMappingMemory.java src/org/binarytranslator/generic/memory/ByteAddressedMemory.java src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java Added Paths: ----------- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/CountingInstructionFactory.java src/org/binarytranslator/arch/arm/hardware/ src/org/binarytranslator/arch/arm/hardware/Coprocessor.java src/org/binarytranslator/arch/arm/hardware/SystemControlCP.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/DBT_Options.java 2007-06-08 14:03:26 UTC (rev 128) @@ -27,35 +27,25 @@ /** Debug binary loading */ public final static boolean debugLoader = true; - /** Are unimplemented system calls are fatal? */ + /** Are unimplemented system calls fatal? */ public final static boolean unimplementedSystemCallsFatal = false; - // -oO Translation settings Oo- - /** The file that is currently being executed. */ public static String executableFile; /** Arguments given to the executable.*/ public static String[] executableArguments = null; - /** - * The initial optimisation level - */ + /** The initial optimisation level */ public static int initialOptLevel = 0; - /** - * Instructions to translate for an optimisation level 0 trace - */ + /** Instructions to translate for an optimisation level 0 trace */ public static int instrOpt0 = 684; - /** - * Instructions to translate for an optimisation level 1 trace - */ + /** Instructions to translate for an optimisation level 1 trace */ public static int instrOpt1 = 1500; - /** - * Instructions to translate for an optimisation level 2 trace - */ + /** Instructions to translate for an optimisation level 2 trace */ public static int instrOpt2 = 1500; /** @@ -65,9 +55,7 @@ */ public final static boolean optimizeBackwardBranches = true; - /** - * Set this to true to record uncaught branch instructions - */ + /** Set this to true to record uncaught branch instructions */ public static boolean plantUncaughtBranchWatcher = false; /** Should direct branches be resolved before dynamic branches? */ @@ -101,69 +89,46 @@ */ public static boolean debugBranchResolution = true; - /** - * In PPC2IR, print cfg. - */ + /** During code translation, print information about the creation of basic blocks. */ public final static boolean debugCFG = false; - // -oO Runtime debugging options Oo- - - /** - * Debug using GDB? - */ + /** Debug using GDB? */ public static boolean gdbStub = false; - /** - * GDB stub port - */ + /** GDB stub port */ public static int gdbStubPort = 1234; + + /** Print debug information during the translation of instructions. */ + public static boolean debugTranslation = true; - /** - * In ProcessSpace, print syscall numbers. - */ + /** In ProcessSpace, print syscall numbers. */ public static boolean debugSyscall = false; - /** - * In ProcessSpace, print syscall numbers. - */ + /** In ProcessSpace, print syscall numbers. */ public static boolean debugSyscallMore = false; - /** - * Print out various messages about the emulator starting. - */ + /** Print out various messages about the emulator starting. */ public static boolean debugRuntime = true; - /** - * Print out messages from the memory system - */ + /** Print out messages from the memory system */ public static boolean debugMemory = false; - /** - * Print out process space between instructions - */ + /** Print out process space between instructions */ public final static boolean debugPS = false; - /** - * When printing process space, omit floating point registers. - */ + /** When printing process space, omit floating point registers. */ public final static boolean debugPS_OmitFP = false; - /** - * The user ID for the user running the command - */ + /** The user ID for the user running the command */ public final static int UID = 1000; - /** - * The group ID for the user running the command - */ + /** The group ID for the user running the command */ public final static int GID = 100; /** Stores the arguments given to the DBT by the user. These are NOT the arguments given to the executable. */ private final static HashMap<String, String> dbtArguments = new HashMap<String, String>(); - /** - * Read and parse the command line arguments. - */ + /** Read and parse the command line arguments. */ public static void parseArguments(String[] args) { try { Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/Main.java 2007-06-08 14:03:26 UTC (rev 128) @@ -95,10 +95,10 @@ System.err.println("Error accesing file: " + args[0] + ". " + e.getMessage()); return; } - catch (Error e) { + /*catch (Error e) { System.err.println(e.getMessage()); return; - } + }*/ report("Sucessfully created process."); @@ -129,10 +129,10 @@ public static void onExit(int exitcode) { System.out.println("\nProgram has finished. Exitcode: " + exitcode); - try { - ps.branchInfo.saveAsXML("/tmp/profile.xml"); + /*try { + //ps.branchInfo.saveAsXML("/tmp/profile.xml"); } catch (IOException e) { e.printStackTrace(); - } + }*/ } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-06-08 14:03:26 UTC (rev 128) @@ -372,7 +372,7 @@ @Override protected int translateInstruction(Laziness lazy, int pc) { - int nextAddr = translator.translateInstruction(pc, (ARM_Laziness)lazy); + int nextAddr = translator.translateInstruction(pc, (ARM_Laziness)lazy); return nextAddr; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-06-08 14:03:26 UTC (rev 128) @@ -227,6 +227,8 @@ return decode(instruction, _defaultFactory); } + public static int fastpathCount = 0; + /** * Decodes a binary ARM instruction. This method will use the supplied {@link ARM_InstructionFactory} * to create an object representation of the decoded instruction. @@ -241,8 +243,24 @@ */ static <T> T decode(int instruction, ARM_InstructionFactory<T> factory) { - int bits_27_25 = Utils.getBits(instruction, 25, 27); - return prefixDecoders[bits_27_25].decode(instruction, factory); + if (ARM_Options.DATAPROCESSING_DECODER_FASTPATH) { + + //Check condition!=never? + if ((instruction & 0xF0000000) != 0xF0000000) { + + if ((instruction & 0x0F000000) == 0x02000000) { + fastpathCount++; + return factory.createDataProcessing(instruction); + } + } + + int bits_27_25 = Utils.getBits(instruction, 25, 27); + return prefixDecoders[bits_27_25].decode(instruction, factory); + } + else { + int bits_27_25 = Utils.getBits(instruction, 25, 27); + return prefixDecoders[bits_27_25].decode(instruction, factory); + } } /** @@ -254,11 +272,11 @@ */ interface ARM_InstructionFactory<T> { T createDataProcessing(int instr); + T createSwap(int instr); T createSingleDataTransfer(int instr); T createBlockDataTransfer(int instr); T createIntMultiply(int instr); T createLongMultiply(int instr); - T createSwap(int instr); T createSoftwareInterrupt(int instr); T createBranch(int instr); T createBranchExchange(int instr); @@ -274,7 +292,7 @@ * A default implementation of the ARM instruction factory, which will create the * appropriate classes from the {@link ARM_Instructions} namespace. */ - static class DefaultFactory implements ARM_InstructionFactory<ARM_Instructions.Instruction> { + private static class DefaultFactory implements ARM_InstructionFactory<ARM_Instructions.Instruction> { public Instruction createBlockDataTransfer(int instr) { return new MultipleDataTransfer(instr); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-06-08 14:03:26 UTC (rev 128) @@ -30,12 +30,12 @@ protected final ARM_Registers regs; /** The interpreter factory is creating the final instructions, which implement the Interpreter.Instruction interface. */ - protected final InterpreterFactory instructionFactory; + protected final ARM_InstructionFactory<ARM_Instruction> instructionFactory; public ARM_Interpreter(ARM_ProcessSpace ps) { this.ps = ps; this.regs = ps.registers; - instructionFactory = new InterpreterFactory(); + instructionFactory = new CountingInstructionFactory<ARM_Instruction>(new InterpreterFactory()); } /** Decodes the instruction at the given address.*/ @@ -51,7 +51,12 @@ return instruction; } + @Override + public String toString() { + return instructionFactory.toString(); + } + private abstract static class ResolvedOperand { protected int value; Added: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java (rev 0) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-06-08 14:03:26 UTC (rev 128) @@ -0,0 +1,6 @@ +package org.binarytranslator.arch.arm.decoder; + +public class ARM_Options { + public final static boolean FLAG_LAZINESS = false; + public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; +} Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-05-21 17:43:21 UTC (rev 127) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-06-08 14:03:26 UTC (rev 128) @@ -1,6 +1,7 @@ package org.binarytranslator.arch.arm.decoder; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; import org.binarytranslator.arch.arm.decoder.ARM_InstructionDecoder.ARM_InstructionFactory; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.OperandWrapper; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.DataProcessing.Opcode; @@ -44,7 +45,30 @@ this.pc = pc; this.lazy = lazy; - int instruction = ps.memory.loadInstruction32(pc); + int instruction; + try { + instruction = ps.memory.loadInstruction32(pc); + } + catch (NullPointerException e) { + if (DBT_Options.debugTranslation) + System.out.print(String.format("Exception while reading instruction from: 0x%x. ", pc)); + + if (arm2ir.getNumInstructions() == 0) { + if (DBT_Options.debugTranslation) + System.out.println("Planting exception instead."); + + arm2ir.appendThrowBadInstruction(lazy, pc); + return -1; + } + else { + if (DBT_Options.debugTranslation) + System.out.println("Planting return from trace instead."); + + arm2ir.appendTraceExit(lazy, new OPT_IntConstantOperand(pc)); + return -1; + } + + } ARM_Instruction instr = ARM_InstructionDecoder.decode(instruction, translatorFactory); if (instr.getCondition() != Condition.AL) { @@ -120,7 +144,7 @@ OperandWrapper operand) { ResolvedOperand result = new ResolvedOperand_WithoutShifterCarryOut( translator, operand); - return result.getValue(); + return result.getValue().copy(); } /** @@ -240,19 +264,19 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); translator.arm2ir.appendInstruction(Binary.create( - INT_SHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(31))); + INT_SHR, resultRegister.copyRO(), shiftedOperand.copy(), new OPT_IntConstantOperand(31))); break; case LSL: @@ -266,18 +290,18 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), new OPT_IntConstantOperand(0)) ); break; case LSR: @@ -293,25 +317,25 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - normal case translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 - shift >= 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), new OPT_IntConstantOperand(0)) ); break; case ROR: /* * return Integer.rotateRight(value, shiftAmount); */ - translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand, shiftAmount); + translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand.copy(), shiftAmount.copy()); break; case RRX: @@ -326,13 +350,13 @@ curBlock.deleteNormalOut(); curBlock.insertOut(nextBlock); curBlock.insertOut(block1); - translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); + translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister.copyRO(), resultRegister.copy(), new OPT_IntConstantOperand(0x80000000))); break; default: @@ -453,33 +477,33 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block4); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block4.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block4.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation.copyRO(), shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - shift < 32 && shift != 0 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount) ); - translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount.copy()) ); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount.copy(), new OPT_IntConstantOperand(-1)) ); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp.copy()); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - shift >= 32 translator.arm2ir.setCurrentBlock(block3); block3.insertOut(nextBlock); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); - translator.arm2ir.appendInstruction(Binary.create(INT_MUL, resultRegister, getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise + translator.arm2ir.appendInstruction(Binary.create(INT_MUL, resultRegister.copyRO(), getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 4 - shift == 0 translator.arm2ir.setCurrentBlock(block4); block4.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), shiftedOperand.copy())); break; case LSL: @@ -497,26 +521,26 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block6); curBlock.insertOut(block1); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation.copyRO(), shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); + translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - Shift >= 32 translator.arm2ir.setCurrentBlock(block3); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation.copyRO(), shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); block3.insertOut(block4); block3.insertOut(block5); @@ -529,13 +553,13 @@ //block 5 - Shift == 32 translator.arm2ir.setCurrentBlock(block5); block5.insertOut(nextBlock); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 0); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), 0); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 6 - shift == 0 translator.arm2ir.setCurrentBlock(block6); block6.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), shiftedOperand.copy())); break; case LSR: @@ -554,26 +578,26 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block6); curBlock.insertOut(block1); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block6.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 - shift != 0 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(block2); block1.insertOut(block3); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation.copyRO(), shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.GREATER_EQUAL(), block3.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1))); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); - translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, shiftAmount)); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount.copy(), new OPT_IntConstantOperand(-1))); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - Shift >= 32 translator.arm2ir.setCurrentBlock(block3); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, new OPT_IntConstantOperand(0)) ); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), new OPT_IntConstantOperand(0)) ); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation.copyRO(), shiftAmount.copy(), new OPT_IntConstantOperand(32), OPT_ConditionOperand.EQUAL(), block5.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); block3.insertOut(block4); block3.insertOut(block5); @@ -586,13 +610,13 @@ //block 5 - Shift == 32 translator.arm2ir.setCurrentBlock(block5); block5.insertOut(nextBlock); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), 31); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 6 - shift == 0 translator.arm2ir.setCurrentBlock(block6); block6.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), shiftedOperand.copy())); break; case ROR: @@ -606,20 +630,20 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(block2); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, shiftAmount.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), block2.makeJumpTarget(), OPT_BranchProfileOperand.unlikely())); //block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand, shiftAmount); - translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount, new OPT_IntConstantOperand(-1)) ); - translator.arm2ir.appendInstruction(Binary.create(INT_AND, tmp, tmp, new OPT_IntConstantOperand(0x1F)) ); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp); + translator.arm2ir.appendRotateRight(resultRegister, shiftedOperand.copy(), shiftAmount.copy()); + translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount.copy(), new OPT_IntConstantOperand(-1)) ); + translator.arm2ir.appendInstruction(Binary.create(INT_AND, tmp.copyRO(), tmp.copy(), new OPT_IntConstantOperand(0x1F)) ); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 2 translator.arm2ir.setCurrentBlock(block2); - translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister, shiftedOperand)); + translator.arm2ir.appendInstruction(Move.create(INT_MOVE, resultRegister.copyRO(), shiftedOperand.copy())); break; case RRX: @@ -633,17 +657,17 @@ curBlock.deleteNormalOut(); curBlock.insertOut(block1); curBlock.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand, new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); block1.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister, resultRegister, new OPT_IntConstantOperand(0x80000000))); + translator.arm2ir.appendInstruction(Binary.create(INT_OR, resultRegister.copyRO(), resultRegister.copy(), new OPT_IntConstantOperand(0x80000000))); //nextBlock translator.arm2ir.setCurrentBlock(nextBlock); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 0); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), 0); break; default: @@ -683,7 +707,6 @@ } public int getSuccessor(int pc) { - //if this instruction is not a jump, then we can tell what the next instruction will be. return pc + 4; } @@ -733,7 +756,7 @@ break; case LS: - translateCondition_LS(nextInstruction); + translateCondition_LS(nextInstruction, condBlock); break; case LT: @@ -798,19 +821,31 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } - private void translateCondition_LS(OPT_BasicBlock nextInstruction) { + private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); OPT_Operand carry = arm2ir.getCarryFlag(); OPT_Operand zero = arm2ir.getZeroFlag(); - OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); - arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, - new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + OPT_RegisterOperand result = arm2ir.getTempInt(0); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + +/* cond1.deleteNormalOut(); + cond1.insertOut(cond2); + cond1.insertOut(actualInstruction); + + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + + arm2ir.setCurrentBlock(cond2); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(Goto.create(GOTO, nextInstruction.makeJumpTarget())); + cond2.deleteNormalOut(); + cond2.insertOut(nextInstruction); + cond2.insertOut(actualInstruction);*/ } private void translateCondition_GT(OPT_BasicBlock nextInstruction) { @@ -823,7 +858,7 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, overflow, OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } private void translateCondition_LE(OPT_BasicBlock nextInstruction) { @@ -836,7 +871,7 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, overflow, OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); } public Condition getCondition() { @@ -901,7 +936,7 @@ arm2ir.appendTraceExit(lazy, result); } else { - arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result.copy()) ); } } @@ -917,19 +952,19 @@ protected final void setAddFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { //set the carry flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, OPT_ConditionOperand.CARRY_FROM_ADD(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), result.copy(), lhs.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); //set the overflow flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs, rhs, OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ @@ -952,7 +987,7 @@ arm2ir.appendTraceExit(lazy, result); } else { - arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result.copy()) ); } } @@ -969,19 +1004,19 @@ //set the carry flag to not(Borrow) OPT_ConditionOperand notBorrowFromSub = OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(); arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs, rhs, notBorrowFromSub, new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs.copy(), rhs.copy(), notBorrowFromSub, new OPT_BranchProfileOperand())); //set the overflow flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs, rhs, OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } public int getSuccessor(int pc) { @@ -1039,7 +1074,7 @@ } } else { - arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result) ); + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(Rd), result.copy()) ); } } @@ -1053,11 +1088,11 @@ //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -1178,7 +1213,7 @@ //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. arm2ir.setCurrentBlock(addWithCarry); - arm2ir.appendInstruction(Binary.create(INT_ADD, result, result, new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); addWithCarry.insertOut(addWithoutCarry); //Finally, add the second operands to the result @@ -1209,7 +1244,7 @@ //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). arm2ir.setCurrentBlock(subWithCarry); - arm2ir.appendInstruction(Binary.create(INT_SUB, result, result, new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_SUB, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); subWithCarry.insertOut(subWithoutCarry); //Finally, subtract the second operands from the result @@ -1359,7 +1394,7 @@ OPT_RegisterOperand tmp = arm2ir.getTempInt(0); arm2ir.appendInstruction(Unary.create(INT_NOT, tmp, operand2)); - arm2ir.appendInstruction(Binary.create(INT_AND, result, operand1, tmp)); + arm2ir.appendInstruction(Binary.create(INT_AND, result, operand1, tmp.copy())); setLogicalResult(result); } } @@ -1442,14 +1477,14 @@ OPT_RegisterOperand rotation = arm2ir.getTempInt(1); //rotation = (memAddr & 0x3) * 8 - arm2ir.appendInstruction(Binary.create(INT_AND, rotation, memAddr, new OPT_IntConstantOperand(0x3))); - arm2ir.appendInstruction(Binary.create(INT_SHL, rotation, rotation, new OPT_IntConstantOperand(3))); - arm2ir.appendRotateRight(result, tmp, rotation); + arm2ir.appendInstruction(Binary.create(INT_AND, rotation, memAddr.copy(), new OPT_IntConstantOperand(0x3))); + arm2ir.appendInstruction(Binary.create(INT_SHL, rotation.copyRO(), rotation.copy(), new OPT_IntConstantOperand(3))); + arm2ir.appendRotateRight(result, tmp.copy(), rotation.copy()); } else { - ps.memory.translateLoadUnsigned8(memAddr, tmp); + ps.memory.translateLoadUnsigned8(memAddr.copy(), tmp); ps.memory.translateStore8(memAddr, arm2ir.getRegister(Rm)); - arm2ir.appendInstruction(Move.create(INT_MOVE, result, tmp)); + arm2ir.appendInstruction(Move.create(INT_MOVE, result, tmp.copy())); } } @@ -1508,19 +1543,19 @@ //post-indexing, backward reading //startAddress -= (registerCount + (transferPC ? 1 : 0)) * 4; OPT_Operand offset = new OPT_IntConstantOperand((registerCount + (transferPC ? 1 : 0)) * 4); - arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress, startAddress, offset)); + arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress.copyRO(), startAddress.copy(), offset)); } else { //pre-indexing, backward-reading //startAddress -= (registerCount + (transferPC ? 2 : 1)) * 4 OPT_Operand offset = new OPT_IntConstantOperand((registerCount + (transferPC ? 2 : 1)) * 4); - arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress, startAddress, offset)); + arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress.copyRO(), startAddress.copy(), offset)); } } else { if (postIndexing) { //post-indexing, forward reading //startAddress -= 4; OPT_Operand offset = new OPT_IntConstantOperand(4); - arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress, startAddress, offset)); + arm2ir.appendInstruction(Binary.create(INT_SUB, startAddress.copyRO(), startAddress.copyRO(), offset)); } else { //pre-indexing, forward reading //no need to adjust the start address @@ -1528,7 +1563,7 @@ } OPT_RegisterOperand nextAddress = arm2ir.getTempInt(1); - arm2ir.appendInstruction(Move.create(INT_MOVE, nextAddress, startAddress)); + arm2ir.appendInstruction(Move.create(INT_MOVE, nextAddress, startAddress.copy())); //are we supposed to load or store multiple registers? if (isLoad) { @@ -1536,7 +1571,7 @@ while (registersToTransfer[nextReg] != -1) { //nextAddress += 4; - arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress, nextAddress, new OPT_IntConstantOperand(4))); + arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress.copyRO(), nextAddress.copy(), new OPT_IntConstantOperand(4))); OPT_RegisterOperand target = arm2ir.getRegister(registersToTransfer[nextReg++]); ps.memory.translateLoad32(nextAddress, target); @@ -1545,13 +1580,13 @@ //if we also transferred the program counter if (transferPC) { //nextAddress += 4; - arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress, nextAddress, new OPT_IntConstantOperand(4))); + arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress.copyRO(), nextAddress.copy(), new OPT_IntConstantOperand(4))); OPT_RegisterOperand regPC = arm2ir.getRegister(ARM_Registers.PC); - ps.memory.translateLoad32(nextAddress, regPC); + ps.memory.translateLoad32(nextAddress.copy(), regPC); //first translate the register write back - translateWriteback(startAddress, nextAddress); + translateWriteback(startAddress.copyRO(), nextAddress.copyRO()); //shall we switch to thumb mode? OPT_BasicBlock finishInstruction = arm2ir.createBlockAfterCurrentNotInCFG(); @@ -1563,7 +1598,7 @@ currentBlock.deleteNormalOut(); currentBlock.insertOut(switchToARMBlock); currentBlock.insertOut(switchToThumbBlock); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), regPC, new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), switchToThumbBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), regPC.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), switchToThumbBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); arm2ir.appendInstruction(Goto.create(GOTO, switchToARMBlock.makeJumpTarget())); //Yes, switch to thumb mode @@ -1577,7 +1612,7 @@ //No, don't switch to thumb mode arm2ir.setCurrentBlock(switchToARMBlock); switchToARMBlock.insertOut(finishInstruction); - arm2ir.appendInstruction(Binary.create(INT_AND, regPC, regPC, new OPT_IntConstantOperand(0xFFFFFFFE))); + arm2ir.appendInstruction(Binary.create(INT_AND, regPC.copyRO(), regPC.copy(), new OPT_IntConstantOperand(0xFFFFFFFE))); OPT_Instruction call_setArmMode = createCallToRegisters("setThumbMode", "(Z)V", 1); Call.setParam(call_setArmMode, 1, new OPT_IntConstantOperand(0)); arm2ir.appendCustomCall(call_setArmMode); @@ -1593,18 +1628,18 @@ while (registersToTransfer[nextReg] != -1) { //nextAddress += 4; - arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress, nextAddress, new OPT_IntConstantOperand(4))); - ps.memory.translateStore32(nextAddress, arm2ir.getRegister(registersToTransfer[nextReg++])); + arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress.copyRO(), nextAddress.copy(), new OPT_IntConstantOperand(4))); + ps.memory.translateStore32(nextAddress.copy(), arm2ir.getRegister(registersToTransfer[nextReg++])); } //also transfer the program counter, if requested so if (transferPC) { - arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress, nextAddress, new OPT_IntConstantOperand(4))); - ps.memory.translateStore32(nextAddress, new OPT_IntConstantOperand(pc + 8)); + arm2ir.appendInstruction(Binary.create(INT_ADD, nextAddress.copyRO(), nextAddress.copy(), new OPT_IntConstantOperand(4))); + ps.memory.translateStore32(nextAddress.copy(), new OPT_IntConstantOperand(pc + 8)); } } - translateWriteback(startAddress, nextAddress); + translateWriteback(startAddress.copyRO(), nextAddress.copyRO()); } private void translateWriteback(OPT_RegisterOperand startAddress, OPT_RegisterOperand nextAddress) { @@ -1757,17 +1792,17 @@ if (accumulate) { OPT_Operand operand3 = arm2ir.getRegister(Rn); - arm2ir.appendInstruction(Binary.create(INT_ADD, result, result, operand3)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3)); } if (updateConditionCodes) { //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -1799,35 +1834,35 @@ if (unsigned) { //treat the original ints as unsigned, so get rid of the signs for the longs - arm2ir.appendInstruction(Binary.create(LONG_AND, operand1, operand1, new OPT_LongConstantOperand(0xFFFFFFFF))); - arm2ir.appendInstruction(Binary.create(LONG_AND, operand2, operand2, new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand1.copyRO(), operand1.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand2.copyRO(), operand2.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); } //multiply the two operands - arm2ir.appendInstruction(Binary.create(LONG_MUL, result, operand1, operand2)); + arm2ir.appendInstruction(Binary.create(LONG_MUL, result.copyRO(), operand1.copy(), operand2.copy())); if (accumulate) { //treat the accum. value as an unsigned value OPT_Operand operand3 = arm2ir.getRegister(getRdLow()); OPT_RegisterOperand tmp = arm2ir.getTempLong(0); arm2ir.appendInstruction(Unary.create(INT_2LONG, tmp, operand3)); - arm2ir.appendInstruction(Binary.create(LONG_AND, tmp, tmp, new OPT_LongConstantOperand(0xFFFFFFFF))); - arm2ir.appendInstruction(Binary.create(LONG_ADD, result, result, tmp)); + arm2ir.appendInstruction(Binary.create(LONG_AND, tmp.copyRO(), tmp.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_ADD, result.copyRO(), result.copy(), tmp.copy())); operand3 = arm2ir.getRegister(getRdHigh()); - arm2ir.appendInstruction(Unary.create(INT_2LONG, tmp, operand3)); - arm2ir.appendInstruction(Binary.create(LONG_SHL, tmp, tmp, new OPT_IntConstantOperand(32))); - arm2ir.appendInstruction(Binary.create(INT_ADD, result, result, operand3)); + arm2ir.appendInstruction(Unary.create(INT_2LONG, tmp.copyRO(), operand3)); + arm2ir.appendInstruction(Binary.create(LONG_SHL, tmp.copyRO(), tmp.copy(), new OPT_IntConstantOperand(32))); + arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3.copy())); } if (updateConditionCodes) { //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getNegativeFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getZeroFlag(), result, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -1897,7 +1932,8 @@ } public void translate() { - arm2ir.appendSystemCall(lazy, pc); + arm2ir.appendInstruction(Move.create(INT_MOVE, arm2ir.getRegister(ARM_Registers.PC), new OPT_IntConstantOperand(pc))); + arm2ir.appendSystemCall(lazy); arm2ir.appendBranch(arm2ir.getRegister(ARM_Registers.PC), lazy, BranchType.INDIRECT_BRANCH); } @@ -1926,7 +1962,7 @@ else { OPT_RegisterOperand tmp = arm2ir.getTempInt(0); arm2ir.appendInstruction(Unary.create(INT_NEG, tmp, positiveOffset)); - return tmp; + return tmp.copy(); } } @@ -1948,7 +1984,7 @@ //add the offset to the base register OPT_RegisterOperand tmp = arm2ir.getTempInt(0); arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, base, resolveOffset())); - return tmp; + return tmp.copy(); } public void translate() { @@ -1989,12 +2025,12 @@ //make sure that we're not loosing the address due to the shifting OPT_RegisterOperand adrCopy = arm2ir.getTempInt(0); - arm2ir.appendInstruction(Move.create(INT_MOVE, adrCopy, address)); + arm2ir.appendInstruction(Move.create(INT_MOVE, adrCopy, address.copy())); //rotation = (address & 0x3) * 8 - arm2ir.appendInstruction(Binary.create(INT_AND, rotation, address, new OPT_IntConstantOperand(0x3))); - arm2ir.appendInstruction(Binary.create(INT_SHL, rotation, rotation, new OPT_IntConstantOperand(3))); - arm2ir.appendRotateRight(value, value, rotation); + arm2ir.appendInstruction(Binary.create(INT_AND, rotation, address.copy(), new OPT_IntConstantOperand(0x3))); + arm2ir.appendInstruction(Binary.create(INT_SHL, rotation.copyRO(), rotation.copy(), new OPT_IntConstantOperand(3))); + arm2ir.appendRotateRight(value.copyRO(), value.copy(), rotation.copy()); //allow further usage of the memory address address = adrCopy; @@ -2026,7 +2062,7 @@ case Word: OPT_RegisterOperand tmp = arm2ir.getTempInt(0); arm2ir.appendInstruction(Binary.create(INT_AND, tmp, address, new OPT_IntConstantOperand(0xFFFFFFFE))); - ps.memory.translateStore32(tmp, value); + ps.memory.translateStore32(tmp.copyRO(), value); break; case HalfWord: @@ -2055,7 +2091,7 @@ OPT_RegisterOperand writeBackTarget = arm2ir.getRegister(Rn); if (preIndexing) { - arm2ir.appendInstruction(Move.create(INT_MOVE, writeBackTarget, address)); + arm2ir.appendInstruction(Move.create(INT_MOVE, writeBackTarget, address.copy())); } else { //add... [truncated message content] |
From: <mic...@us...> - 2007-06-19 09:10:03
|
Revision: 134 http://svn.sourceforge.net/pearcolator/?rev=134&view=rev Author: michael_baer Date: 2007-06-19 02:10:03 -0700 (Tue, 19 Jun 2007) Log Message: ----------- - Made ARM_InstructionVisitor a subclass of ARM_Instructions - Moved decoder utilities class to package generic.decoder Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java Added Paths: ----------- src/org/binarytranslator/generic/decoder/Utils.java Removed Paths: ------------- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java src/org/binarytranslator/arch/arm/decoder/Utils.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-06-19 09:10:03 UTC (rev 134) @@ -16,6 +16,7 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.SingleDataTransfer; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.SoftwareInterrupt; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Swap; +import org.binarytranslator.arch.arm.decoder.ARM_Instructions.ARM_InstructionVisitor; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Instruction.Condition; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.generic.decoder.DisassembledInstruction; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionDecoder.java 2007-06-19 09:10:03 UTC (rev 134) @@ -1,6 +1,7 @@ package org.binarytranslator.arch.arm.decoder; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.*; +import org.binarytranslator.generic.decoder.Utils; /** * This class decodes an ARM or Thumb instruction and uses a user-supplied Deleted: src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/ARM_InstructionVisitor.java 2007-06-19 09:10:03 UTC (rev 134) @@ -1,22 +0,0 @@ -package org.binarytranslator.arch.arm.decoder; - -import org.binarytranslator.arch.arm.decoder.ARM_Instructions.*; - -/** An interface that supports iterating over ARM instructions using the visitor pattern. */ -public interface ARM_InstructionVisitor { - - void visit(DataProcessing instr); - void visit(SingleDataTransfer instr); - void visit(IntMultiply instr); - void visit(LongMultiply instr); - void visit(Swap instr); - void visit(BlockDataTransfer instr); - void visit(SoftwareInterrupt instr); - void visit(Branch instr); - void visit(BranchExchange instr); - void visit(CoprocessorDataTransfer instr); - void visit(CoprocessorDataProcessing instr); - void visit(CoprocessorRegisterTransfer instr); - void visit(MoveFromStatusRegister instr); - void visit(MoveToStatusRegister instr); -} Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-06-19 09:10:03 UTC (rev 134) @@ -3,6 +3,7 @@ import org.binarytranslator.DBT; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.OperandWrapper.ShiftType; import org.binarytranslator.arch.arm.os.process.ARM_Registers; +import org.binarytranslator.generic.decoder.Utils; /** * In the ARM decoder model, the decoding and usage (translating/interpreting/disassembling) of instructions @@ -1672,4 +1673,22 @@ visitor.visit(this); } } + + public interface ARM_InstructionVisitor { + + void visit(DataProcessing instr); + void visit(SingleDataTransfer instr); + void visit(IntMultiply instr); + void visit(LongMultiply instr); + void visit(Swap instr); + void visit(BlockDataTransfer instr); + void visit(SoftwareInterrupt instr); + void visit(Branch instr); + void visit(BranchExchange instr); + void visit(CoprocessorDataTransfer instr); + void visit(CoprocessorDataProcessing instr); + void visit(CoprocessorRegisterTransfer instr); + void visit(MoveFromStatusRegister instr); + void visit(MoveToStatusRegister instr); + } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-06-19 09:10:03 UTC (rev 134) @@ -11,6 +11,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; import org.binarytranslator.generic.branch.BranchLogic.BranchType; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.decoder.Utils; import com.sun.org.apache.bcel.internal.generic.InstructionFactory; Deleted: src/org/binarytranslator/arch/arm/decoder/Utils.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-06-18 17:06:44 UTC (rev 133) +++ src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-06-19 09:10:03 UTC (rev 134) @@ -1,196 +0,0 @@ -package org.binarytranslator.arch.arm.decoder; - -import org.binarytranslator.DBT; - -public class Utils { - - /** - * Checks if a bit is set within a word. - * @param word - * The word that is being examined. - * @param bit - * The number of the bit that is to be checked, starting from zero. - * @return - * True, if the given bit is set within the word, false otherwise. - */ - static final boolean getBit(int word, int bit) { - if (DBT.VerifyAssertions) - DBT._assert(bit >= 0 && bit <= 31); - return (word & (1 << bit)) != 0; - } - - /** - * Same functions as {@link #getBit(int, int)} for shorts. - */ - static final boolean getBit(short word, int bit) { - if (DBT.VerifyAssertions) - DBT._assert(bit >= 0 && bit <= 15); - return (word & (1 << bit)) != 0; - } - - /** - * Extracts a subsequence of bits from a word and shifts the beginning of that subsequence to - * a zero based-number. - * A call to <code>getBits(0xFF, 2, 3)</code> would return 0x3. - * @param word - * The word that is to be examined. - * @param from - * The first bit (starting from 0) that is to be extracted. - * @param to - * The last bit (starting from 0) that is to be extracted from the word. - * @return - * A zero-based version of the bit sequence. - */ - static final int getBits(int word, int from, int to) { - if (DBT.VerifyAssertions) - DBT._assert(from < to && from >= 0 && to < 31); - - return (word & ((1 << (to + 1)) - 1)) >> from; - } - - /** - * Same function as {@link #getBits(int, int, int)} for shorts. - */ - static final int getBits(short word, int from, int to) { - if (DBT.VerifyAssertions) - DBT._assert(from < to && from >= 0 && to <= 15); - - return (word & ((1 << (to + 1)) - 1)) >> from; - } - - /** - * Sign extends a given value. - * @param value - * The value to sign extends. - * @param bitsUsed - * The number bits used within this value. - * @return - * A sign extended value. - */ - static int signExtend(int value, int bitsUsed) { - return (value << (32 - bitsUsed)) >> (32 - bitsUsed); - } - - /** - * Returns true, if the addition of both operands as unsigned integers will cause an overflow. - * At the moment, this converts both values to longs and checks if the 33rd bit (which actually represents the carry) - * overflows. - */ - public static boolean unsignedAddOverflow(int operand1, int operand2) { - long value1 = (long)operand1 & 0xFFFFFFFFL; - long value2 = (long)operand2 & 0xFFFFFFFFL; - - return ((value1 + value2) & 0x100000000L) != 0; - } - - /** - * Returns true, if the subtraction of both operand1 - operand2 (both unsigned) will issue a borrow. - */ - public static boolean unsignedSubOverflow(int operand1, int operand2) { - operand1 += Integer.MIN_VALUE; - operand2 += Integer.MIN_VALUE; - - return operand1 < operand2; - } - - /** - * Returns true, if the addition of both operands as signed integers will cause an overflow. - * This basically checks <code>operand1 + operand2 > Integer.MAX_VALUE</code>. - */ - public static boolean signedAddOverflow(int operand1, int operand2) { - return operand1 > Integer.MAX_VALUE - operand2; - } - - /** - * Returns true, if the subtraction of operand1 from operand (as signed integers) - * will cause an overflow. - * This basically checks <code>operand1 - operand2 < Integer.MIN_VALUE</code>. - */ - public static boolean signedSubOverflow(int operand1, int operand2) { - // if the MSB is already set in any of the operands, then no overflow can - // occur - if (operand1 >= 0) { - return (operand2 < 0) && ((operand1-operand2) < 0); - } - else { - return (operand2 > 0) && ((operand1-operand2) > 0); - } - } - - /** - * Performs a number of sanity tests that make sure that the above functions are working the - * manner described before.*/ - public static void runSanityTests() { - if (!Utils.unsignedAddOverflow(1, -1)) { - throw new RuntimeException("Error"); - } - - if (!Utils.unsignedAddOverflow(-1, -1)) { - throw new RuntimeException("Error"); - } - - if (!Utils.unsignedAddOverflow(-1, 1)) { - throw new RuntimeException("Error"); - } - - if (Utils.unsignedAddOverflow(10000, 10000)) { - throw new RuntimeException("Error"); - } - - if (Utils.unsignedSubOverflow(-1, 1)) { - throw new RuntimeException("Error"); - } - - if (!Utils.unsignedSubOverflow(1, -1)) { - throw new RuntimeException("Error"); - } - - if (Utils.unsignedSubOverflow(-1, -1)) { - throw new RuntimeException("Error"); - } - - if (Utils.unsignedSubOverflow(10, 0)) { - throw new RuntimeException("Error"); - } - - if (!Utils.unsignedSubOverflow(0, 10)) { - throw new RuntimeException("Error"); - } - - if (!Utils.signedAddOverflow(0x70000000, 0x10000000)) { - throw new RuntimeException("Error"); - } - - if (Utils.signedAddOverflow(0x90000000, 0x10000000)) { - throw new RuntimeException("Error"); - } - - if (!Utils.signedAddOverflow(0x50000000, 0x50000000)) { - throw new RuntimeException("Error"); - } - - if (Utils.signedAddOverflow(0x60000000, 0x10000000)) { - throw new RuntimeException("Error"); - } - - if (Utils.signedAddOverflow(0x10000000, 0x60000000)) { - throw new RuntimeException("Error"); - } - - if (!Utils.signedSubOverflow(0x80000000, 0x30000000)) { - throw new RuntimeException("Error"); - } - - if (!Utils.signedSubOverflow(0x30000000, 0x80000000)) { - throw new RuntimeException("Error"); - } - - if (!Utils.signedSubOverflow(0, 0x80000000)) { - throw new RuntimeException("Error"); - } - - if (Utils.signedSubOverflow(0, 0x70000000)) { - throw new RuntimeException("Error"); - } - } -} Copied: src/org/binarytranslator/generic/decoder/Utils.java (from rev 133, src/org/binarytranslator/arch/arm/decoder/Utils.java) =================================================================== --- src/org/binarytranslator/generic/decoder/Utils.java (rev 0) +++ src/org/binarytranslator/generic/decoder/Utils.java 2007-06-19 09:10:03 UTC (rev 134) @@ -0,0 +1,196 @@ +package org.binarytranslator.generic.decoder; + +import org.binarytranslator.DBT; + +public class Utils { + + /** + * Checks if a bit is set within a word. + * @param word + * The word that is being examined. + * @param bit + * The number of the bit that is to be checked, starting from zero. + * @return + * True, if the given bit is set within the word, false otherwise. + */ + public static final boolean getBit(int word, int bit) { + if (DBT.VerifyAssertions) + DBT._assert(bit >= 0 && bit <= 31); + return (word & (1 << bit)) != 0; + } + + /** + * Same functions as {@link #getBit(int, int)} for shorts. + */ + public static final boolean getBit(short word, int bit) { + if (DBT.VerifyAssertions) + DBT._assert(bit >= 0 && bit <= 15); + return (word & (1 << bit)) != 0; + } + + /** + * Extracts a subsequence of bits from a word and shifts the beginning of that subsequence to + * a zero based-number. + * A call to <code>getBits(0xFF, 2, 3)</code> would return 0x3. + * @param word + * The word that is to be examined. + * @param from + * The first bit (starting from 0) that is to be extracted. + * @param to + * The last bit (starting from 0) that is to be extracted from the word. + * @return + * A zero-based version of the bit sequence. + */ + public static final int getBits(int word, int from, int to) { + if (DBT.VerifyAssertions) + DBT._assert(from < to && from >= 0 && to < 31); + + return (word & ((1 << (to + 1)) - 1)) >> from; + } + + /** + * Same function as {@link #getBits(int, int, int)} for shorts. + */ + public static final int getBits(short word, int from, int to) { + if (DBT.VerifyAssertions) + DBT._assert(from < to && from >= 0 && to <= 15); + + return (word & ((1 << (to + 1)) - 1)) >> from; + } + + /** + * Sign extends a given value. + * @param value + * The value to sign extends. + * @param bitsUsed + * The number bits used within this value. + * @return + * A sign extended value. + */ + public static int signExtend(int value, int bitsUsed) { + return (value << (32 - bitsUsed)) >> (32 - bitsUsed); + } + + /** + * Returns true, if the addition of both operands as unsigned integers will cause an overflow. + * At the moment, this converts both values to longs and checks if the 33rd bit (which actually represents the carry) + * overflows. + */ + public static boolean unsignedAddOverflow(int operand1, int operand2) { + long value1 = (long)operand1 & 0xFFFFFFFFL; + long value2 = (long)operand2 & 0xFFFFFFFFL; + + return ((value1 + value2) & 0x100000000L) != 0; + } + + /** + * Returns true, if the subtraction of both operand1 - operand2 (both unsigned) will issue a borrow. + */ + public static boolean unsignedSubOverflow(int operand1, int operand2) { + operand1 += Integer.MIN_VALUE; + operand2 += Integer.MIN_VALUE; + + return operand1 < operand2; + } + + /** + * Returns true, if the addition of both operands as signed integers will cause an overflow. + * This basically checks <code>operand1 + operand2 > Integer.MAX_VALUE</code>. + */ + public static boolean signedAddOverflow(int operand1, int operand2) { + return operand1 > Integer.MAX_VALUE - operand2; + } + + /** + * Returns true, if the subtraction of operand1 from operand (as signed integers) + * will cause an overflow. + * This basically checks <code>operand1 - operand2 < Integer.MIN_VALUE</code>. + */ + public static boolean signedSubOverflow(int operand1, int operand2) { + // if the MSB is already set in any of the operands, then no overflow can + // occur + if (operand1 >= 0) { + return (operand2 < 0) && ((operand1-operand2) < 0); + } + else { + return (operand2 > 0) && ((operand1-operand2) > 0); + } + } + + /** + * Performs a number of sanity tests that make sure that the above functions are working the + * manner described before.*/ + public static void runSanityTests() { + if (!Utils.unsignedAddOverflow(1, -1)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedAddOverflow(-1, -1)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedAddOverflow(-1, 1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedAddOverflow(10000, 10000)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(-1, 1)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedSubOverflow(1, -1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(-1, -1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(10, 0)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedSubOverflow(0, 10)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedAddOverflow(0x70000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x90000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedAddOverflow(0x50000000, 0x50000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x60000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x10000000, 0x60000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0x80000000, 0x30000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0x30000000, 0x80000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0, 0x80000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedSubOverflow(0, 0x70000000)) { + throw new RuntimeException("Error"); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-06-20 13:53:32
|
Revision: 139 http://svn.sourceforge.net/pearcolator/?rev=139&view=rev Author: michael_baer Date: 2007-06-20 06:53:32 -0700 (Wed, 20 Jun 2007) Log Message: ----------- - Added missing .copy() calls within AbstractCodeTranslator - Removed unused options from DBT_Options Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-06-20 13:25:36 UTC (rev 138) +++ src/org/binarytranslator/DBT_Options.java 2007-06-20 13:53:32 UTC (rev 139) @@ -19,7 +19,7 @@ public class DBT_Options { /** Remove features that will only work on jikes? */ - public final static boolean buildForSunVM = true; + public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ public final static boolean profileDuringInterpretation = true; @@ -36,9 +36,6 @@ /** Arguments given to the executable.*/ public static String[] executableArguments = null; - /** The initial optimisation level */ - public static int initialOptLevel = 0; - /** Instructions to translate for an optimisation level 0 trace */ public static int instrOpt0 = 684; @@ -61,32 +58,16 @@ /** Should direct branches be resolved before dynamic branches? */ public static boolean resolveDirectBranchesFirst = true; - /** - * Use global branch information rather than local (within the trace) - * information when optimisation level is greater than or equal to this value - */ - public static int globalBranchLevel = 3; - - /** - * Set this to true to translate only one instruction at a time. - */ + /** Set this to true to translate only one instruction at a time. */ public static boolean singleInstrTranslation = false; - /** - * Eliminate unneeded filling of register - */ + /** Eliminate unneeded filling of register */ public final static boolean eliminateRegisterFills = true; - // -oO Translation debugging options Oo- - - /** - * Print dissassembly of translated instructions. - */ + /** Print dissassembly of translated instructions. */ public static boolean debugInstr = true; - /** - * Print information about the lazy resolution of branch addresses... - */ + /** Print information about the lazy resolution of branch addresses...*/ public static boolean debugBranchResolution = true; /** During code translation, print information about the creation of basic blocks. */ @@ -113,12 +94,6 @@ /** Print out messages from the memory system */ public static boolean debugMemory = false; - /** Print out process space between instructions */ - public final static boolean debugPS = false; - - /** When printing process space, omit floating point registers. */ - public final static boolean debugPS_OmitFP = false; - /** The user ID for the user running the command */ public final static int UID = 1000; @@ -180,10 +155,6 @@ debugSyscall = Boolean.parseBoolean(value); } else if (arg.equalsIgnoreCase("-X:dbt:debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:globalBranchLevel")) { - globalBranchLevel = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("-X:dbt:initialOptLevel")) { - initialOptLevel = Integer.parseInt(value); } else if (arg.equalsIgnoreCase("-X:dbt:instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (arg.equalsIgnoreCase("-X:dbt:instrOpt1")) { Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-06-20 13:25:36 UTC (rev 138) +++ src/org/binarytranslator/Main.java 2007-06-20 13:53:32 UTC (rev 139) @@ -99,7 +99,7 @@ report("Sucessfully created process."); - if (DBT_Options.debugPS) { + if (DBT_Options.debugRuntime) { System.out.println("***** INITIAL PROCESS SPACE *****\n"); System.out.println(ps); } Modified: src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java 2007-06-20 13:25:36 UTC (rev 138) +++ src/org/binarytranslator/generic/decoder/AbstractCodeTranslator.java 2007-06-20 13:53:32 UTC (rev 139) @@ -661,7 +661,7 @@ OPT_BasicBlock fallThrough = createBlockAfterCurrent(); OPT_Instruction switchInstr; - switchInstr = LookupSwitch.create(LOOKUPSWITCH, targetAddress, null, null, fallThrough.makeJumpTarget(), null, 0); + switchInstr = LookupSwitch.create(LOOKUPSWITCH, targetAddress.copyRO(), null, null, fallThrough.makeJumpTarget(), null, 0); appendInstruction(switchInstr); UnresolvedJumpInstruction unresolvedInfo = new UnresolvedJumpInstruction(switchInstr, (Laziness)lazyStateAtJump.clone(), currentPC, branchType); @@ -669,7 +669,7 @@ setCurrentBlock(fallThrough); appendRecordUncaughtBranch(currentPC, targetAddress.copyRO(), branchType, retAddr); - appendTraceExit((Laziness) lazyStateAtJump.clone(), targetAddress.copyRO()); + appendTraceExit((Laziness) lazyStateAtJump.clone(), targetAddress); } @@ -855,7 +855,7 @@ // Copy the value into the register specified by gc.resultReg. appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand( - gc.resultReg, VM_TypeReference.Int), nextPc)); + gc.resultReg, VM_TypeReference.Int), nextPc.copy())); resolveLaziness(laziness); appendInstruction(Goto.create(GOTO, finishBlock.makeJumpTarget())); currentBlock.deleteNormalOut(); @@ -1086,7 +1086,7 @@ Call.setParam(s, 0, psRef); // Reference to ps, sets 'this' pointer Call.setParam(s, 1, new OPT_IntConstantOperand(pc)); // Address of branch // instruction - Call.setParam(s, 2, destination); // Destination of branch value + Call.setParam(s, 2, destination.copy()); // Destination of branch value Call.setParam(s, 3, new OPT_IntConstantOperand(branchType.ordinal())); // Branch type Call.setParam(s, 4, new OPT_IntConstantOperand(retAddr)); // return address // value This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-02 16:02:39
|
Revision: 144 http://svn.sourceforge.net/pearcolator/?rev=144&view=rev Author: michael_baer Date: 2007-07-02 09:02:39 -0700 (Mon, 02 Jul 2007) Log Message: ----------- Introduced a command line parameter to select the desired execution controller. Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/execution/ExecutionController.java src/org/binarytranslator/generic/execution/InterpreterController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-07-02 16:01:43 UTC (rev 143) +++ src/org/binarytranslator/DBT_Options.java 2007-07-02 16:02:39 UTC (rev 144) @@ -13,6 +13,8 @@ import java.util.Map; import java.util.Map.Entry; +import org.binarytranslator.generic.execution.ExecutionController; + /** * Options for controlling the emulator */ @@ -44,6 +46,8 @@ /** Instructions to translate for an optimisation level 2 trace */ public static int instrOpt2 = 1500; + + public static ExecutionController.Type executionController = ExecutionController.Type.Translator; /** * Favour backward branch optimization. Translate backward branch addresses @@ -135,42 +139,51 @@ catch (NumberFormatException e) { throw new Error("Argument " + arg + " is not a valid integer."); } + catch (Exception e) { + throw new Error("Error while parsing argument '" + arg + "'.", e); + } } } - /** - * Parses a single argument into the options class. - */ + /** Parses a single argument into the options class. */ private static void parseSingleArgument(String arg, String value) { + + if (!arg.startsWith("-X:dbt:")) { + throw new Error("Invalid argument. Argument prefix '-X:dbt:' expected."); + } + + arg = arg.substring(7); - if (arg.equalsIgnoreCase("-X:dbt:debugInstr")) { + if (arg.equalsIgnoreCase("debugInstr")) { debugInstr = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:debugRuntime")) { + } else if (arg.equalsIgnoreCase("debugRuntime")) { debugRuntime = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:debugBranchResolution")) { + } else if (arg.equalsIgnoreCase("debugBranchResolution")) { debugBranchResolution = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:debugMemory")) { + } else if (arg.equalsIgnoreCase("debugMemory")) { debugMemory = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:debugSyscall")) { + } else if (arg.equalsIgnoreCase("debugSyscall")) { debugSyscall = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:debugSyscallMore")) { + } else if (arg.equalsIgnoreCase("debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:instrOpt0")) { + } else if (arg.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("-X:dbt:instrOpt1")) { + } else if (arg.equalsIgnoreCase("instrOpt1")) { instrOpt1 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("-X:dbt:instrOpt2")) { + } else if (arg.equalsIgnoreCase("instrOpt2")) { instrOpt2 = Integer.parseInt(value); - } else if (arg.equalsIgnoreCase("-X:dbt:singleInstrTranslation")) { + } else if (arg.equalsIgnoreCase("singleInstrTranslation")) { singleInstrTranslation = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:resolveDirectBranchesFirst")) { + } else if (arg.equalsIgnoreCase("resolveDirectBranchesFirst")) { resolveDirectBranchesFirst = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:gdbStub")) { + } else if (arg.equalsIgnoreCase("gdbStub")) { gdbStub = Boolean.parseBoolean(value); - } else if (arg.equalsIgnoreCase("-X:dbt:gdbStubPort")) { + } else if (arg.equalsIgnoreCase("gdbStubPort")) { gdbStubPort = Integer.parseInt(value); + } else if (arg.equalsIgnoreCase("controller")) { + executionController = ExecutionController.Type.valueOf(value); } else { - throw new Error("DBT Options: Unknown emulator option " + arg); + throw new Error("Unknown DBT option: " + arg); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-07-02 16:01:43 UTC (rev 143) +++ src/org/binarytranslator/Main.java 2007-07-02 16:02:39 UTC (rev 144) @@ -104,19 +104,30 @@ System.out.println(ps); } + //on SUN's VM, only the interpreter has been tested + if (DBT_Options.buildForSunVM) { + DBT_Options.executionController = ExecutionController.Type.Interpreter; + + } + //Create an execution controller and pass execution on to it - ExecutionController controller; + ExecutionController controller = null; - if (DBT_Options.buildForSunVM) { - controller = new InterpreterController(ps); - } - else { - if (DBT_Options.gdbStub) { + switch (DBT_Options.executionController) { + case Interpreter: + controller = new InterpreterController(ps); + break; + + case Translator: + controller = new DynamicTranslationController(ps); + break; + + case GDB: controller = new GdbController(DBT_Options.gdbStubPort, ps); - } - else { - controller = new DynamicTranslationController(ps); - } + break; + + default: + throw new Error("Unknown requested controller: " + DBT_Options.executionController); } controller.run(); Modified: src/org/binarytranslator/generic/execution/ExecutionController.java =================================================================== --- src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-02 16:01:43 UTC (rev 143) +++ src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-02 16:02:39 UTC (rev 144) @@ -1,12 +1,22 @@ package org.binarytranslator.generic.execution; +import org.binarytranslator.DBT; import org.binarytranslator.generic.os.process.ProcessSpace; public abstract class ExecutionController { + public enum Type { + Translator, + Interpreter, + GDB + } + protected final ProcessSpace ps; public ExecutionController(ProcessSpace ps) { + if (DBT.VerifyAssertions) + DBT._assert(ps != null); + this.ps = ps; } Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-02 16:01:43 UTC (rev 143) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-02 16:02:39 UTC (rev 144) @@ -18,9 +18,10 @@ while (!ps.finished) { Interpreter.Instruction instruction = interpreter.decode(pc); - System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); + //System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); instruction.execute(); + //System.out.println(ps.toString()); pc = instruction.getSuccessor(pc); if (pc == -1) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-04 16:39:20
|
Revision: 146 http://svn.sourceforge.net/pearcolator/?rev=146&view=rev Author: michael_baer Date: 2007-07-04 09:39:23 -0700 (Wed, 04 Jul 2007) Log Message: ----------- - Added an execution controller that performs predecoded, threaded interpretation Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/execution/ExecutionController.java Added Paths: ----------- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-07-04 15:17:39 UTC (rev 145) +++ src/org/binarytranslator/DBT_Options.java 2007-07-04 16:39:23 UTC (rev 146) @@ -21,7 +21,7 @@ public class DBT_Options { /** Remove features that will only work on jikes? */ - public final static boolean buildForSunVM = false; + public final static boolean buildForSunVM = true; /** Enable the profiling of application during interpretation? */ public final static boolean profileDuringInterpretation = true; @@ -47,6 +47,7 @@ /** Instructions to translate for an optimisation level 2 trace */ public static int instrOpt2 = 1500; + /** Determines how the program will be run (i.e. interpreted, translated etc.) */ public static ExecutionController.Type executionController = ExecutionController.Type.Translator; /** Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-07-04 15:17:39 UTC (rev 145) +++ src/org/binarytranslator/Main.java 2007-07-04 16:39:23 UTC (rev 146) @@ -10,6 +10,7 @@ import java.io.File; +import org.binarytranslator.generic.execution.PredecodingThreadedInterpreter; import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; @@ -106,7 +107,7 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { - DBT_Options.executionController = ExecutionController.Type.Interpreter; + DBT_Options.executionController = ExecutionController.Type.PredecodingThreadedInterpreter; } @@ -114,6 +115,11 @@ ExecutionController controller = null; switch (DBT_Options.executionController) { + + case PredecodingThreadedInterpreter: + controller = new PredecodingThreadedInterpreter(ps); //new PredecodingThreadedInterpreter(ps); + break; + case Interpreter: controller = new InterpreterController(ps); break; Modified: src/org/binarytranslator/generic/execution/ExecutionController.java =================================================================== --- src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-04 15:17:39 UTC (rev 145) +++ src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-04 16:39:23 UTC (rev 146) @@ -8,6 +8,7 @@ public enum Type { Translator, Interpreter, + PredecodingThreadedInterpreter, GDB } Added: src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java (rev 0) +++ src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-04 16:39:23 UTC (rev 146) @@ -0,0 +1,75 @@ +package org.binarytranslator.generic.execution; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public final class PredecodingThreadedInterpreter extends ExecutionController { + private HashMap<Integer, List<Interpreter.Instruction>> traceCache = new HashMap<Integer, List<Interpreter.Instruction>>(); + private Interpreter interpreter; + + private List<Interpreter.Instruction> getTrace(int pc) { + List<Interpreter.Instruction> cachedTrace = traceCache.get(pc); + + if (cachedTrace != null) + return cachedTrace; + + int traceStart = pc; + ArrayList<Interpreter.Instruction> newTrace = new ArrayList<Interpreter.Instruction>(5); + + while (true) { + Interpreter.Instruction instruction = interpreter.decode(pc); + pc = instruction.getSuccessor(pc); + newTrace.add(instruction); + + //is the successor to this instruction known? + if (pc == -1) { + + //No, so stop the trace after this instruction + if (newTrace.size() > 3) { + //add this trace to the trace cache, if it contains enough instructions + traceCache.put(traceStart, newTrace); + } + + break; + } + } + + return newTrace; + } + + private void executeTrace(List<Interpreter.Instruction> trace, int pc) { + + Iterator<Interpreter.Instruction> instructions = trace.iterator(); + while (instructions.hasNext()) { + Interpreter.Instruction instr = instructions.next(); + instr.execute(); + pc = instr.getSuccessor(pc); + + if (pc != -1) + ps.setCurrentInstructionAddress(pc); + } + } + + public PredecodingThreadedInterpreter(ProcessSpace ps) { + super(ps); + } + + @Override + public void run() { + interpreter = ps.createInstructionInterpreter(); + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + + List<Interpreter.Instruction> trace = getTrace(pc); + executeTrace(trace, pc); + pc = ps.getCurrentInstructionAddress(); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-11 16:34:30
|
Revision: 151 http://svn.sourceforge.net/pearcolator/?rev=151&view=rev Author: michael_baer Date: 2007-07-11 09:34:25 -0700 (Wed, 11 Jul 2007) Log Message: ----------- - Make sure that the runtime linker does not return a local symbol when we're trying to resolve a global symbol. Modified Paths: -------------- src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java Modified: src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java 2007-07-09 10:42:27 UTC (rev 150) +++ src/org/binarytranslator/arch/arm/os/process/loader/ARM_RuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) @@ -70,7 +70,7 @@ if (symbol.isUndefined()) { String symbolName = strTab.lookup(symbol.nameIdx); - value = resolveSymbolAddress(symbolName); + value = resolveSymbolAddress(symbolName, lib); if (value == -1) { //we allow only weak symbols to be unresolved Modified: src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-09 10:42:27 UTC (rev 150) +++ src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) @@ -119,6 +119,7 @@ * This function is the main entry point into the dynamic linker and will steer the whole * linking process. */ + @Override public final void link() throws IOException { ELF_File.DynamicSection dynSection = file.getDynamicSection(); @@ -193,7 +194,7 @@ */ protected void callInitRoutines() throws IOException { //the linker has a special symbol that determines if we're currently starting up - int dl_starting_up = resolveSymbolAddress("_dl_starting_up"); + int dl_starting_up = resolveSymbolAddress("_dl_starting_up", null); if (dl_starting_up != -1) ps.memory.store32(dl_starting_up, 1); @@ -392,10 +393,13 @@ * * @param symbol * The name of the symbol that is to be resolved. + * @param obj + * The shared object for which we are trying to resolve the symbol address. Local symbols from + * this object will be returned as a match as well. * @return * The address of the symbol or -1, if the symbol's address could not be resolved. */ - protected final int resolveSymbolAddress(String symbol) throws IOException { + protected final int resolveSymbolAddress(String symbol, SharedObject obj) throws IOException { Iterator<SharedObject> libs = libraries.iterator(); //iterate over the symbol table of every library that we already loaded @@ -406,8 +410,10 @@ //see if <symbol> is defined within this library SymbolTable.Entry entry = hashTab.lookup(symbol); - if (entry != null && !entry.isUndefined()) - return entry.value + lib.loadedAt; + if (entry != null && !entry.isUndefined() && entry.binding != SymbolTable.STB_LOCAL) { + if (entry.binding == SymbolTable.STB_GLOBAL || lib == obj) + return entry.value + lib.loadedAt; + } } return -1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-07-29 13:13:15
|
Revision: 152 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=152&view=rev Author: michael_baer Date: 2007-07-29 06:13:16 -0700 (Sun, 29 Jul 2007) Log Message: ----------- - Made profiling during interpretation a functionality provided by the ExecutionController - Added new ExecutionController - Restructured branch profiling slightly Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java src/org/binarytranslator/generic/branchprofile/BranchProfile.java src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/decoder/Interpreter.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java src/org/binarytranslator/generic/os/process/ProcessSpace.java Added Paths: ----------- src/org/binarytranslator/generic/decoder/Disassembler.java src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -9,7 +9,6 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; -import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.decoder.Utils; @@ -23,7 +22,7 @@ * @author Michael Baer */ public class ARM_Interpreter implements Interpreter { - + /** The process space that we're interpreting.*/ protected final ARM_ProcessSpace ps; @@ -31,7 +30,7 @@ protected final ARM_Registers regs; /** The interpreter factory is creating the final instructions, which implement the Interpreter.Instruction interface. */ - protected final ARM_InstructionFactory<ARM_Instruction> instructionFactory; + protected final InterpreterFactory instructionFactory; public ARM_Interpreter(ARM_ProcessSpace ps) { this.ps = ps; @@ -41,9 +40,11 @@ /** Decodes the instruction at the given address.*/ public Instruction decode(int pc) { - + ARM_Instruction instruction; + instructionFactory.setInstructionAddress(pc); + if ((pc & 1) != 0) { short binaryInstruction = (short)ps.memory.loadInstruction16(pc & 0xFFFFFFFE); instruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction, instructionFactory); @@ -54,7 +55,7 @@ } if (instruction.getCondition() != Condition.AL) { - return new ConditionalDecorator(instruction); + return new ConditionalDecorator(instruction, pc); } return instruction; @@ -123,7 +124,7 @@ if (operand.getRegister() == ARM_Registers.PC) value = regs.readPC(); else - value =regs.get(operand.getRegister()); + value = regs.get(operand.getRegister()); value += operand.getOffset(); return; @@ -364,43 +365,66 @@ * instruction (or not). The instruction classes itself do not check any conditions. */ private final class ConditionalDecorator implements Interpreter.Instruction { + /** The conditional instruction. */ protected final ARM_Instruction conditionalInstruction; - private final Condition condition; + + /** The address of the successor of the conditional instruction. Can be -1, if it cannot be determined statically. */ + private final int conditionTrueSuccessor; + + /** The successor of this instruction, if the condition evaluates to false.*/ + private final int conditionFalseSuccessor; + + /** The address of the successor of this instrction if it is constant, otherwise -1. */ + private final int successorInstruction; + + /** The address of this instruction. */ + private final int instructionAddress; /** Decorates an ARM interpreter instruction, by making it execute conditionally. */ - protected ConditionalDecorator(ARM_Instruction i) { - conditionalInstruction = i; - this.condition = i.getCondition(); + protected ConditionalDecorator(ARM_Instruction i, int pc) { + this.conditionalInstruction = i; + + conditionTrueSuccessor = conditionalInstruction.getSuccessor(pc); + boolean inThumbMode = (pc & 1) == 0; + + if (conditionTrueSuccessor == pc + 4 && !inThumbMode) + successorInstruction = conditionTrueSuccessor; //ARM may have conditional instruction that are not jumps + else + successorInstruction = -1; + + conditionFalseSuccessor = pc + (inThumbMode ? 2 : 4); + instructionAddress = pc; } public void execute() { + if (isConditionTrue()) { - int nextInstruction = conditionalInstruction.getSuccessor(ps.getCurrentInstructionAddress()); conditionalInstruction.execute(); - if (nextInstruction != -1) - ps.setCurrentInstructionAddress(nextInstruction); + if (conditionTrueSuccessor != -1) { + ps.setCurrentInstructionAddress(conditionTrueSuccessor); + } + + if (successorInstruction != -1) { + ps.branchInfo.profileBranch(instructionAddress, conditionTrueSuccessor); + } } else { - ps.setCurrentInstructionAddress(ps.getCurrentInstructionAddress() + (regs.getThumbMode() ? 2 : 4)); + ps.setCurrentInstructionAddress(conditionFalseSuccessor); + + if (successorInstruction != -1) { + ps.branchInfo.profileBranch(instructionAddress, conditionFalseSuccessor); + } } } public int getSuccessor(int pc) { - //if this instruction is not a jump, then we can tell what the next instruction will be. - - int conditionalSuccessor = conditionalInstruction.getSuccessor(pc); - boolean thumbMode = (pc & 0x1) == 1; - - if (conditionalSuccessor == pc + 4 && !thumbMode) - return conditionalSuccessor; //ARM may have conditional non-jump instructions - else - return -1; + return successorInstruction; } /** Return true if the condition required by the conditional instruction is fulfilled, false otherwise.*/ private boolean isConditionTrue() { - switch (condition) { + switch (conditionalInstruction.getCondition()) { case AL: throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); @@ -450,7 +474,7 @@ return regs.isOverflowSet(); default: - throw new RuntimeException("Unexpected condition code: " + condition); + throw new RuntimeException("Unexpected condition code: " + conditionalInstruction.getCondition()); } } @@ -514,10 +538,6 @@ if (i.Rd == ARM_Registers.PC) { if (regs.getThumbMode()) result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } } regs.set(i.Rd, result); @@ -533,13 +553,8 @@ setFlagsForSub(lhs, rhs); int result = lhs - rhs; - if (i.Rd == ARM_Registers.PC) { - if (regs.getThumbMode()) - result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } + if (i.Rd == ARM_Registers.PC && regs.getThumbMode()) { + result |= 1; } regs.set(i.Rd, result); @@ -595,8 +610,13 @@ * out value. The value of the barrel shifter is stored within this variable. */ protected boolean shifterCarryOut; - protected DataProcessing_Logical(ARM_Instructions.DataProcessing instr) { + protected DataProcessing_Logical(ARM_Instructions.DataProcessing instr, int instructionAddress) { super(instr); + + if (DBT_Options.profileDuringInterpretation) { + if (i.getOpcode() == Opcode.MOV && i.operand2.getType() == OperandWrapper.Type.Register && i.operand2.getRegister() == ARM_Registers.LR) + ps.branchInfo.registerReturnSite(instructionAddress); + } } /** If the given OperandWrapper involves shifting a register, then this function will decoder the shift @@ -622,13 +642,6 @@ if (regs.getThumbMode()) result |= 1; - - if (DBT_Options.profileDuringInterpretation) { - if (i.getOpcode() == Opcode.MOV && i.operand2.getType() == OperandWrapper.Type.Register && i.operand2.getRegister() == ARM_Registers.LR) - ps.branchInfo.registerReturn(regs.get(ARM_Registers.PC), result); - else - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), result, BranchType.INDIRECT_BRANCH); - } } regs.set(i.Rd, result); @@ -651,8 +664,8 @@ /** Binary and. <code>Rd = op1 & op2 </code>.*/ private final class DataProcessing_And extends DataProcessing_Logical { - protected DataProcessing_And(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_And(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -665,8 +678,8 @@ /** Exclusive or. <code>Rd = op1 ^ op2 </code>.*/ private final class DataProcessing_Eor extends DataProcessing_Logical { - protected DataProcessing_Eor(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Eor(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -804,8 +817,8 @@ * <code>Flags = op1 & op2</code>*/ private final class DataProcessing_Tst extends DataProcessing_Logical { - protected DataProcessing_Tst(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Tst(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -818,8 +831,8 @@ * <code>Flags = op1 ^ op2</code> */ private final class DataProcessing_Teq extends DataProcessing_Logical { - protected DataProcessing_Teq(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Teq(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -859,8 +872,8 @@ /** Binary or. <code>Rd = op1 | op2</code>. */ private final class DataProcessing_Orr extends DataProcessing_Logical { - protected DataProcessing_Orr(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Orr(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -872,8 +885,8 @@ private final class DataProcessing_Mov extends DataProcessing_Logical { - protected DataProcessing_Mov(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Mov(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -888,8 +901,8 @@ * <code>Rd = op1 & (~op2)</code>.*/ private final class DataProcessing_Bic extends DataProcessing_Logical { - protected DataProcessing_Bic(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Bic(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -904,8 +917,8 @@ * <code>Rd = ~op2</code>.*/ private final class DataProcessing_Mvn extends DataProcessing_Logical { - protected DataProcessing_Mvn(ARM_Instructions.DataProcessing instr) { - super(instr); + protected DataProcessing_Mvn(ARM_Instructions.DataProcessing instr, int instructionAddress) { + super(instr, instructionAddress); } @Override @@ -1000,22 +1013,26 @@ /** Should writeback be performed? */ private final boolean doWriteback; - public BlockDataTransfer(ARM_Instructions.BlockDataTransfer instr) { + public BlockDataTransfer(ARM_Instructions.BlockDataTransfer instr, int instructionAddress) { i = instr; transferPC = i.transferRegister(ARM_Registers.PC); int regCount = 0; - for (int i = 0; i <= 14; i++) + for (int i = 0; i <= 14; i++) { if (this.i.transferRegister(i)) { registersToTransfer[regCount++] = i; } + } registersToTransfer[regCount] = -1; if (transferPC) regCount++; + if (DBT_Options.profileDuringInterpretation) + ps.branchInfo.registerReturnSite(instructionAddress); + if (!i.incrementBase) { if (i.postIndexing) { //post-indexing, backward reading @@ -1095,9 +1112,6 @@ nextAddress += 4; int newpc = ps.memory.load32(nextAddress); - if (DBT_Options.profileDuringInterpretation) - ps.branchInfo.registerReturn(regs.get(ARM_Registers.PC), newpc); - if (i.forceUser) { //when we are transferring the PC with a forced-user transfer, then we also want to //restore the CPSR from the SPSR. @@ -1177,30 +1191,18 @@ public void execute() { - int destination; - BranchType branchType; - - if (i.offset.getType() != OperandWrapper.Type.Immediate) { - branchType = BranchType.INDIRECT_BRANCH; - } - else { - branchType = BranchType.DIRECT_BRANCH; - } - + int destination; destination = regs.readPC() + ResolvedOperand.resolve(regs, i.offset); - if (DBT_Options.profileDuringInterpretation) { - if (i.link) { - ps.branchInfo.registerCall(regs.get(ARM_Registers.PC), destination, regs.get(ARM_Registers.PC) + i.size()); - } - else { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), destination, branchType); - } - } - //if we're supposed to link, then write the previous address into the link register if (i.link) { - regs.set(ARM_Registers.LR, regs.get(ARM_Registers.PC) + i.size()); + int returnAddress = regs.get(ARM_Registers.PC) + i.size(); + + if (DBT_Options.profileDuringInterpretation) { + ps.branchInfo.registerCallSite(regs.get(ARM_Registers.PC), destination, returnAddress); + } + + regs.set(ARM_Registers.LR, returnAddress); } if (regs.getThumbMode()) @@ -1273,12 +1275,13 @@ //if we're supposed to link, then write the previous address into the link register if (i.link) { - regs.set(ARM_Registers.LR, regs.readPC() - (regs.getThumbMode() ? 2 : 4)); - ps.branchInfo.registerCall(regs.get(ARM_Registers.PC), targetAddress, regs.get(ARM_Registers.PC) + i.size()); + int returnAddress = regs.readPC() - i.size(); + regs.set(ARM_Registers.LR, returnAddress); + + if (DBT_Options.profileDuringInterpretation) { + ps.branchInfo.registerCallSite(regs.get(ARM_Registers.PC), targetAddress, returnAddress); + } } - else { - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), targetAddress, BranchType.DIRECT_BRANCH); - } //jump to the new address regs.set(ARM_Registers.PC, targetAddress); @@ -1372,8 +1375,8 @@ //get rid of the signs, if we're supposed to do unsigned multiplication if (i.unsigned) { - operand1 = operand1 & 0xFFFFFFFF; - operand2 = operand2 & 0xFFFFFFFF; + operand1 &= 0xFFFFFFFF; + operand2 &= 0xFFFFFFFF; } // calculate the result @@ -1634,11 +1637,6 @@ //finally, write the variable into a register regs.set(i.Rd, value); - - if (DBT_Options.profileDuringInterpretation) { - if (i.Rd == ARM_Registers.PC) - ps.branchInfo.registerBranch(regs.get(ARM_Registers.PC), value, BranchType.INDIRECT_BRANCH); - } } else { //we are store a value from a register to memory. @@ -1743,6 +1741,8 @@ * the ARM_InstructionDecoder, which uses an abstract factory pattern to decode an instruction. */ private class InterpreterFactory implements ARM_InstructionFactory<ARM_Instruction> { + + private int instructionAddress; public ARM_Instruction createDataProcessing(int instr) { ARM_Instructions.DataProcessing i = new ARM_Instructions.DataProcessing(instr); @@ -1753,21 +1753,21 @@ case ADD: return new DataProcessing_Add(i); case AND: - return new DataProcessing_And(i); + return new DataProcessing_And(i, instructionAddress); case BIC: - return new DataProcessing_Bic(i); + return new DataProcessing_Bic(i, instructionAddress); case CMN: return new DataProcessing_Cmn(i); case CMP: return new DataProcessing_Cmp(i); case EOR: - return new DataProcessing_Eor(i); + return new DataProcessing_Eor(i, instructionAddress); case MOV: - return new DataProcessing_Mov(i); + return new DataProcessing_Mov(i, instructionAddress); case MVN: - return new DataProcessing_Mvn(i); + return new DataProcessing_Mvn(i, instructionAddress); case ORR: - return new DataProcessing_Orr(i); + return new DataProcessing_Orr(i, instructionAddress); case RSB: return new DataProcessing_Rsb(i); case RSC: @@ -1777,9 +1777,9 @@ case SUB: return new DataProcessing_Sub(i); case TEQ: - return new DataProcessing_Teq(i); + return new DataProcessing_Teq(i, instructionAddress); case TST: - return new DataProcessing_Tst(i); + return new DataProcessing_Tst(i, instructionAddress); case CLZ: return new DataProcessing_Clz(i); @@ -1788,8 +1788,12 @@ } } + public void setInstructionAddress(int pc) { + instructionAddress = pc; + } + public ARM_Instruction createBlockDataTransfer(int instr) { - return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr)); + return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr), instructionAddress); } public ARM_Instruction createBranch(int instr) { @@ -1854,7 +1858,7 @@ } public ARM_Instruction createBlockDataTransfer(short instr) { - return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr)); + return new BlockDataTransfer(new ARM_Instructions.BlockDataTransfer(instr), instructionAddress); } public ARM_Instruction createBranch(short instr) { @@ -1874,21 +1878,21 @@ case ADD: return new DataProcessing_Add(i); case AND: - return new DataProcessing_And(i); + return new DataProcessing_And(i, instructionAddress); case BIC: - return new DataProcessing_Bic(i); + return new DataProcessing_Bic(i, instructionAddress); case CMN: return new DataProcessing_Cmn(i); case CMP: return new DataProcessing_Cmp(i); case EOR: - return new DataProcessing_Eor(i); + return new DataProcessing_Eor(i, instructionAddress); case MOV: - return new DataProcessing_Mov(i); + return new DataProcessing_Mov(i, instructionAddress); case MVN: - return new DataProcessing_Mvn(i); + return new DataProcessing_Mvn(i, instructionAddress); case ORR: - return new DataProcessing_Orr(i); + return new DataProcessing_Orr(i, instructionAddress); case RSB: return new DataProcessing_Rsb(i); case RSC: @@ -1898,9 +1902,9 @@ case SUB: return new DataProcessing_Sub(i); case TEQ: - return new DataProcessing_Teq(i); + return new DataProcessing_Teq(i, instructionAddress); case TST: - return new DataProcessing_Tst(i); + return new DataProcessing_Tst(i, instructionAddress); case CLZ: return new DataProcessing_Clz(i); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,6 +1,5 @@ package org.binarytranslator.arch.arm.decoder; public class ARM_Options { - public final static boolean FLAG_LAZINESS = false; public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; } Modified: src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java =================================================================== --- src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/arch/ppc/decoder/PPC_InstructionDecoder.java 2007-07-29 13:13:16 UTC (rev 152) @@ -3942,7 +3942,7 @@ int target_address = ps.lr; if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -4593,7 +4593,7 @@ int target_address = ps.ctr; if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -11618,7 +11618,7 @@ } if (LK != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } // decode BO @@ -11767,7 +11767,7 @@ } if (lk != 0) { ps.lr = ps.getCurrentInstructionAddress() + 4; - ps.branchInfo.registerCall(ps.getCurrentInstructionAddress(), ps + ps.branchInfo.registerCallSite(ps.getCurrentInstructionAddress(), ps .getCurrentInstructionAddress() + 4, target_address); } ps.setCurrentInstructionAddress(target_address); Modified: src/org/binarytranslator/generic/branchprofile/BranchProfile.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-29 13:13:16 UTC (rev 152) @@ -12,10 +12,12 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.Map.Entry; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -49,10 +51,101 @@ private final SortedMap<Integer, ProcedureInformation> procedures; /** A set of switch like branchs sites and their destinations */ - private final SortedMap<Integer, Set<Integer>> branchSitesAndDestinations; + private final SortedMap<Integer, BranchInformation> branchSites; /** Global branch information */ private static BranchProfile global; + + /** + * Stores information on a single branch location. */ + private final static class BranchInformation { + + /** How often the branch instruction has been executed. */ + private int executionCount; + + /** The target addresses of the branch and how often they have been branched to. */ + private final Map<Integer, Integer> destinationsAndFrequencies; + + public BranchInformation() { + this.destinationsAndFrequencies = new HashMap<Integer, Integer>(); + } + + public BranchInformation(HashMap<Integer, Integer> destinationsAndFrequencies) { + this.destinationsAndFrequencies = destinationsAndFrequencies; + executionCount = 0; + + for (Entry<Integer, Integer> target : destinationsAndFrequencies.entrySet()) { + executionCount += target.getValue(); + } + } + + public void profile(int target) { + executionCount++; + Integer targetCount = destinationsAndFrequencies.get(target); + + targetCount = (targetCount == null) ? 1 : targetCount + 1; + destinationsAndFrequencies.put(target, targetCount); + } + + /** Returns a list of addresses that this branch jumps to. */ + public Set<Integer> getTargets() { + return destinationsAndFrequencies.keySet(); + } + + public Map<Integer, Integer> getTargetsAndFrequencies() { + return destinationsAndFrequencies; + } + + public void registerTargetSite(int target) { + if (destinationsAndFrequencies.get(target) == null) + destinationsAndFrequencies.put(target, 0); + } + + /** + * Loads a {@link BranchInformation} object from an XML element, given that the object + * was previously persisted by {@link #toXML(Document, Element)}. + * @param node + * The XML element that had been provided to {@link #toXML(Document, Element)}. + * @throws IOException + */ + public static BranchInformation fromXML(Element node) throws IOException { + HashMap<Integer, Integer> targetsAndFrequencies = new HashMap<Integer, Integer>(); + + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node target = node.getChildNodes().item(n); + + if (target.getNodeType() != Node.ELEMENT_NODE) + continue; + + if (!target.getNodeName().equals("target")) + throw new IOException("File is not a valid XML branch profile."); + + int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); + int branchCount = Integer.parseInt(((Element)target).getAttribute("address")); + targetsAndFrequencies.put(targetAddress, branchCount); + } + + return new BranchInformation(targetsAndFrequencies); + } + + public void toXML(Document doc, Element parentNode) { + Element branchInfo = parentNode; + + Element targets = doc.createElement("targets"); + + for (Entry<Integer, Integer> branchTarget : destinationsAndFrequencies.entrySet()) { + int targetAddress = branchTarget.getKey(); + int branchCount = branchTarget.getValue(); + + Element branchTargetElement = doc.createElement("target"); + branchInfo.appendChild(branchTargetElement); + branchTargetElement.setAttribute("address", Integer.toString(targetAddress)); + branchTargetElement.setAttribute("branchCount", Integer.toString(branchCount)); + } + + branchInfo.appendChild(targets); + } + } /** * Constructor has 2 functions: (1) when making a local trace we don't want to @@ -62,10 +155,10 @@ public BranchProfile() { if (global == null) { global = this; - branchSitesAndDestinations = new TreeMap<Integer, Set<Integer>>(); + branchSites = new TreeMap<Integer, BranchInformation>(); } else { - branchSitesAndDestinations = global.branchSitesAndDestinations; + branchSites = global.branchSites; } procedures = new TreeMap<Integer, ProcedureInformation>(); } @@ -80,7 +173,7 @@ * @param ret * the address that will be returned to */ - public void registerCall(int pc, int dest, int ret) { + public void registerCallSite(int pc, int dest, int ret) { ProcedureInformation procedure = procedures.get(dest); if (procedure != null) { @@ -90,27 +183,66 @@ procedures.put(dest, procedure); } - registerBranch(pc, dest); + registerDynamicBranchSite(pc, dest); } + + /** + * Register a function return. + * + * @param pc + * the address of the return instruction + */ + public void registerReturnSite(int pc) { + + ProcedureInformation procedure = getLikelyProcedure(pc); + + if (procedure != null) { + procedure.registerReturn(pc); + } + } /** * Register a function return. * * @param pc - * the address of the branch instruction + * the address of the return instruction * @param lr * the return address (value of the link register) */ - public void registerReturn(int pc, int lr) { + public void registerReturnSite(int pc, int lr) { ProcedureInformation procedure = getLikelyProcedure(pc); if (procedure != null) { - procedure.registerReturn(pc, lr); + procedure.registerReturn(pc); } - registerBranch(pc, lr); + registerDynamicBranchSite(pc, lr); } + + /** + * Appends a branch from <code>origin</code> to <code>target</code> to the branch profile. + * + * @param origin + * The address that the branch is taking place from. + * @param target + * The branch target address. + */ + public void registerDynamicBranchSite(int origin, int target) { + //Perform the general branch registration, too + BranchInformation branch = branchSites.get(origin); + + if (branch != null) { + branch.registerTargetSite(target); + // This destination address is already registered + return; + } + else { + branch = new BranchInformation(); + branch.registerTargetSite(target); + branchSites.put(origin, branch); + } + } /** * Given an address within a procedure, returns the (most likely) procedure @@ -128,58 +260,19 @@ } } return null; - } - + } + /** - * Registers a branch from the address <code>origin</code> to the address <code>target</code>. - * The type of branch is determined by <code>type</code>, which is an ordinal from the - * {@link BranchType} enum. + * Records that a branch from <code>origin</code> to <code>target</code> has been observed while the program is running. * * @param origin - * The address from which the branch occurs. + * The address from which the branch took place. * @param target - * The address to which the program is branching. - * @param type - * The most likely type of the branch. This is taken from the {@link BranchType} enum. + * The address to which it took place. */ - public void registerBranch(int origin, int target, BranchType type) { - - switch (type) { - case CALL: - throw new RuntimeException("Use the more specific registerCall() for these cases."); - - case RETURN: - registerReturn(origin, target); - break; - - default: - registerBranch(origin, target); - } + public void profileBranch(int origin, int target) { + throw new RuntimeException("Not yet implemented."); } - - /** - * Appends a recorded branch from <code>origin</code> to <code>target</code> to the branch profile. - * - * @param origin - * The address that the branch is taking place from. - * @param target - * The branch target address. - */ - private void registerBranch(int origin, int target) { - //Perform the general branch registration, too - Set<Integer> dests = branchSitesAndDestinations.get(origin); - - if (dests != null && dests.contains(target)) { - // This destination address is already registered - return; - } - else { - dests = new HashSet<Integer>(); - branchSitesAndDestinations.put(origin, dests); - } - - dests.add(target); - } /** * Returns a list of known branch targets for the branch at address <code>pc</code>. @@ -191,7 +284,8 @@ * translated binary, if this list is not complete. */ public Set<Integer> getKnownBranchTargets(int pc) { - return branchSitesAndDestinations.get(pc); + BranchInformation branch = branchSites.get(pc); + return (branch == null) ? null : branch.getTargets(); } public void loadFromXML(String filename) throws IOException { @@ -234,17 +328,9 @@ if (!siteNode.getNodeName().equals("origin") || siteNode.getNodeType() != Node.ELEMENT_NODE) throw new IOException("File is not a valid XML branch profile."); - int pc = Integer.parseInt(((Element)siteNode).getAttribute("address")); - - for (int n = 0; n < siteNode.getChildNodes().getLength(); n++) { - Node target = siteNode.getChildNodes().item(n); - - if (!target.getNodeName().equals("target") || target.getNodeType() != Node.ELEMENT_NODE) - throw new IOException("File is not a valid XML branch profile."); - - int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); - registerBranch(pc, targetAddress); - } + int address = Integer.parseInt(((Element)siteNode).getAttribute("address")); + BranchInformation branchInfo = BranchInformation.fromXML((Element)siteNode); + branchSites.put(address, branchInfo); } } @@ -289,17 +375,16 @@ Element branchesElement = doc.createElement("branches"); root.appendChild(branchesElement); - - for (int pc : branchSitesAndDestinations.keySet()) { - Element branchSiteElement = doc.createElement("origin"); + + for (Entry<Integer, BranchInformation> branch : branchSites.entrySet()) { + + int address = branch.getKey(); + BranchInformation branchInfo = branch.getValue(); + + Element branchSiteElement = doc.createElement("branch"); branchesElement.appendChild(branchSiteElement); - branchSiteElement.setAttribute("address", Integer.toString(pc)); - - for (int target : getKnownBranchTargets(pc)) { - Element branchTargetElement = doc.createElement("target"); - branchSiteElement.appendChild(branchTargetElement); - branchTargetElement.setAttribute("address", Integer.toString(target)); - } + branchSiteElement.setAttribute("address", Integer.toString(address)); + branchInfo.toXML(doc, branchSiteElement); } //Output the resulting XML document Modified: src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-29 13:13:16 UTC (rev 152) @@ -91,13 +91,12 @@ * * @param pc * the address of the branch instruction - * @param ret - * the address that will be returned to */ - public void registerReturn(int pc, int ret) { + public void registerReturn(int pc) { if (returnSites == null) { returnSites = new HashSet<Integer>(); } + returnSites.add(new Integer(pc)); } @@ -186,11 +185,7 @@ throw new Error("The given XML node is not a valid ProcedureInformation entity."); } } - - - - - + return pi; } } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-07-29 13:13:16 UTC (rev 152) @@ -607,13 +607,15 @@ branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, BranchType.CALL); unresolvedDirectBranches.add(unresolvedJump); - if (branchType == BranchType.CALL) - ps.branchInfo.registerCall(currentPC, targetPC, retAddr); - else - if (branchType == BranchType.RETURN) - ps.branchInfo.registerReturn(currentPC, targetPC); - else - ps.branchInfo.registerBranch(currentPC, targetPC, branchType); + switch (branchType) { + case CALL: + ps.branchInfo.registerCallSite(currentPC, targetPC, retAddr); + break; + + case RETURN: + ps.branchInfo.registerReturnSite(currentPC, targetPC); + break; + } } /** @@ -929,7 +931,7 @@ * the destination of the branch instruction */ public void registerBranchAndLink(int pc, int ret, int dest) { - ps.branchInfo.registerCall(pc, ret, dest); + ps.branchInfo.registerCallSite(pc, ret, dest); } /** Added: src/org/binarytranslator/generic/decoder/Disassembler.java =================================================================== --- src/org/binarytranslator/generic/decoder/Disassembler.java (rev 0) +++ src/org/binarytranslator/generic/decoder/Disassembler.java 2007-07-29 13:13:16 UTC (rev 152) @@ -0,0 +1,46 @@ +package org.binarytranslator.generic.decoder; + +public interface Disassembler { + /** + * Represents an instruction, after it has been decoded by a disassembler. + * The instruction should be printable in the format of the target system's assembly language. + * + * @author Michael Baer + */ + public interface Instruction { + /** + * Shall return the address of the instruction following this one in <i>code order</i>, given that + * the current instruction has been decoded from address <code>pc</code>. + * @param pc + * The address from which this instruction has been decoded. + * @return + * The address of the instruction following this one in code order. + */ + int getSuccessor(int pc); + + /** + * Shall return a string representation of the disassembled instruction. + * We might have used toString() here, but I wanted it to be obvious if a dedicated implementation + * of this method is missing. + * + * @return + * A string representation of the disassembled instruction. + * For example: + * <code> + * ADD r0, r1, #15 + * </code> + * for an ARM ADD instruction. + */ + String asString(); + } + + /** + * Disassemble the instruction at address <code>pc</code> and return an appropriate object representation. + * + * @param pc + * The address at which the instruction resides. + * @return + * An object representation of the said instruction. + */ + Instruction disassemble(int pc); +} Modified: src/org/binarytranslator/generic/decoder/Interpreter.java =================================================================== --- src/org/binarytranslator/generic/decoder/Interpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/decoder/Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,5 +1,9 @@ package org.binarytranslator.generic.decoder; +/** + * TODO: Add comments for this interface. + * + */ public interface Interpreter { public interface Instruction { Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-29 13:13:16 UTC (rev 152) @@ -1,5 +1,6 @@ package org.binarytranslator.generic.execution; +import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -22,12 +23,19 @@ instruction.execute(); //System.out.println(ps.toString()); - pc = instruction.getSuccessor(pc); + int nextInstruction = instruction.getSuccessor(pc); - if (pc == -1) - pc = ps.getCurrentInstructionAddress(); - else - ps.setCurrentInstructionAddress(pc); + if (nextInstruction == -1) { + nextInstruction = ps.getCurrentInstructionAddress(); + + if (DBT_Options.profileDuringInterpretation) + ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); + } + else { + ps.setCurrentInstructionAddress(nextInstruction); + } + + pc = nextInstruction; } } } Modified: src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -8,7 +8,7 @@ import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; -public final class PredecodingThreadedInterpreter extends ExecutionController { +public class PredecodingThreadedInterpreter extends ExecutionController { private final HashMap<Integer, List<Interpreter.Instruction>> traceCache = new HashMap<Integer, List<Interpreter.Instruction>>(); private final Interpreter interpreter; @@ -42,16 +42,19 @@ return newTrace; } - private void executeTrace(List<Interpreter.Instruction> trace, int pc) { + protected void executeTrace(List<Interpreter.Instruction> trace, int pc) { Iterator<Interpreter.Instruction> instructions = trace.iterator(); - while (instructions.hasNext()) { + while (true) { Interpreter.Instruction instr = instructions.next(); instr.execute(); - pc = instr.getSuccessor(pc); - if (pc != -1) + if (instructions.hasNext()) { + pc = instr.getSuccessor(pc); ps.setCurrentInstructionAddress(pc); + } + else + break; } } @@ -61,7 +64,7 @@ } @Override - public void run() { + public final void run() { int pc = ps.getCurrentInstructionAddress(); while (!ps.finished) { Added: src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java (rev 0) +++ src/org/binarytranslator/generic/execution/ProfilingPredecodingInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) @@ -0,0 +1,40 @@ +package org.binarytranslator.generic.execution; + +import java.util.Iterator; +import java.util.List; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.decoder.Interpreter.Instruction; +import org.binarytranslator.generic.os.process.ProcessSpace; + +/** + * Adds runtime profiling capabilities to {@link PredecodingThreadedInterpreter}. + */ +public class ProfilingPredecodingInterpreter extends PredecodingThreadedInterpreter { + + public ProfilingPredecodingInterpreter(ProcessSpace ps) { + super(ps); + } + + @Override + protected void executeTrace(List<Instruction> trace, int pc) { + Iterator<Interpreter.Instruction> instructions = trace.iterator(); + while (true) { + Interpreter.Instruction instr = instructions.next(); + + if (instructions.hasNext()) { + instr.execute(); + pc = instr.getSuccessor(pc); + ps.setCurrentInstructionAddress(pc); + + } + else { + int instructionAdddress = ps.getCurrentInstructionAddress(); + instr.execute(); + pc = ps.getCurrentInstructionAddress(); + ps.branchInfo.profileBranch(instructionAdddress, pc); + break; + } + } + } + +} Modified: src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/os/loader/elf/JavaRuntimeLinker.java 2007-07-29 13:13:16 UTC (rev 152) @@ -35,7 +35,7 @@ private int nextMemoryBlock = 1024*1024*1024; //start mapping libraries at 1GB (0x40000000) /** Maps a library name to a filename. */ - protected final HashMap<String, String> libNames = new HashMap<String, String>();; + protected final HashMap<String, String> libNames = new HashMap<String, String>(); public static class SharedObject { /** The libary's name. */ Modified: src/org/binarytranslator/generic/os/process/ProcessSpace.java =================================================================== --- src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-11 16:34:25 UTC (rev 151) +++ src/org/binarytranslator/generic/os/process/ProcessSpace.java 2007-07-29 13:13:16 UTC (rev 152) @@ -155,15 +155,15 @@ switch (type) { case CALL: - branchInfo.registerCall(location, destination, returnAddress); + branchInfo.registerCallSite(location, destination, returnAddress); return; case RETURN: - branchInfo.registerReturn(location, destination); + branchInfo.registerReturnSite(location, destination); return; default: - branchInfo.registerBranch(location, destination, BranchType.values()[code]); + branchInfo.registerDynamicBranchSite(location, destination); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-02 12:22:43
|
Revision: 153 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=153&view=rev Author: michael_baer Date: 2007-08-02 05:22:44 -0700 (Thu, 02 Aug 2007) Log Message: ----------- - Allowing to load/save branch profiles - Added generic profiling to the Interpreter - Added support for staged emulation Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/generic/branchprofile/BranchProfile.java src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java src/org/binarytranslator/generic/execution/ExecutionController.java src/org/binarytranslator/generic/execution/InterpreterController.java src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java Added Paths: ----------- src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java src/org/binarytranslator/generic/execution/StagedEmulationController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/DBT_Options.java 2007-08-02 12:22:44 UTC (rev 153) @@ -49,7 +49,13 @@ /** Determines how the program will be run (i.e. interpreted, translated etc.) */ public static ExecutionController.Type executionController = ExecutionController.Type.Translator; + + /** A filename to which the runtime profiling information shall be saved. */ + public static String saveProfileToFile = null; + /** A filename from which the runtime profiling information shall be loaded. */ + public static String loadProfileFromFile = null; + /** * Favour backward branch optimization. Translate backward branch addresses * before the next instructions (this is the manner of the 601's branch @@ -183,7 +189,12 @@ gdbStubPort = Integer.parseInt(value); } else if (arg.equalsIgnoreCase("controller")) { executionController = ExecutionController.Type.valueOf(value); - } else { + } else if (arg.equalsIgnoreCase("loadProfile")) { + loadProfileFromFile = arg; + } else if (arg.equalsIgnoreCase("saveProfile")) { + saveProfileToFile = arg; + } + else { throw new Error("Unknown DBT option: " + arg); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/Main.java 2007-08-02 12:22:44 UTC (rev 153) @@ -9,12 +9,14 @@ package org.binarytranslator; import java.io.File; - import org.binarytranslator.generic.execution.PredecodingThreadedInterpreter; import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; import org.binarytranslator.generic.execution.InterpreterController; +import org.binarytranslator.generic.execution.ProfilingInterpreterController; +import org.binarytranslator.generic.execution.ProfilingPredecodingInterpreter; +import org.binarytranslator.generic.execution.StagedEmulationController; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -93,10 +95,6 @@ System.err.println("Error accesing file: " + args[0] + ". " + e.getMessage()); return; } - /*catch (Error e) { - System.err.println(e.getMessage()); - return; - }*/ report("Sucessfully created process."); @@ -108,20 +106,35 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { DBT_Options.executionController = ExecutionController.Type.PredecodingInterpreter; - } + //load a previously saved branch profile from file, if the user requested it + try { + if (DBT_Options.loadProfileFromFile != null) + ps.branchInfo.loadFromXML(DBT_Options.loadProfileFromFile); + } catch (Exception e) { + System.err.println("Error loading branch profile from: " + DBT_Options.loadProfileFromFile); + e.printStackTrace(); + return; + } + //Create an execution controller and pass execution on to it ExecutionController controller = null; switch (DBT_Options.executionController) { + case StagedEmulation: + controller = new StagedEmulationController(ps); + break; + case PredecodingInterpreter: - controller = new PredecodingThreadedInterpreter(ps); //new PredecodingThreadedInterpreter(ps); - break; + controller = DBT_Options.profileDuringInterpretation ? + new ProfilingPredecodingInterpreter(ps) : new PredecodingThreadedInterpreter(ps); + break; case Interpreter: - controller = new InterpreterController(ps); + controller = DBT_Options.profileDuringInterpretation ? + new ProfilingInterpreterController(ps) : new InterpreterController(ps); break; case Translator: @@ -143,10 +156,11 @@ public static void onExit(int exitcode) { System.out.println("\nProgram has finished. Exitcode: " + exitcode); - /*try { - //ps.branchInfo.saveAsXML("/tmp/profile.xml"); - } catch (IOException e) { + try { + if (DBT_Options.saveProfileToFile != null) + ps.branchInfo.saveAsXML(DBT_Options.saveProfileToFile); + } catch (Exception e) { e.printStackTrace(); - }*/ + } } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-02 12:22:44 UTC (rev 153) @@ -20,7 +20,6 @@ import org.binarytranslator.arch.arm.decoder.ARM_Instructions.UndefinedInstruction; import org.binarytranslator.arch.arm.decoder.ARM_Instructions.Instruction.Condition; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; -import org.binarytranslator.generic.decoder.DisassembledInstruction; import org.binarytranslator.generic.decoder.Disassembler; /** Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-02 12:22:44 UTC (rev 153) @@ -385,7 +385,7 @@ this.conditionalInstruction = i; conditionTrueSuccessor = conditionalInstruction.getSuccessor(pc); - boolean inThumbMode = (pc & 1) == 0; + boolean inThumbMode = (pc & 1) == 1; if (conditionTrueSuccessor == pc + 4 && !inThumbMode) successorInstruction = conditionTrueSuccessor; //ARM may have conditional instruction that are not jumps Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-02 12:22:44 UTC (rev 153) @@ -58,11 +58,10 @@ public int translateInstruction(int pc, ARM_Laziness lazy) { this.pc = pc; this.lazy = lazy; - boolean thumb = (pc & 1) != 0; int instruction; try { - if (thumb) + if (inThumb()) instruction = ps.memory.loadInstruction16(pc & 0xFFFFFFFE); else instruction = ps.memory.loadInstruction32(pc); @@ -88,7 +87,7 @@ } ARM_Instruction instr; - if (thumb) + if (inThumb()) instr = ARM_InstructionDecoder.Thumb.decode((short)instruction, translatorFactory); else instr = ARM_InstructionDecoder.ARM32.decode(instruction, translatorFactory); @@ -756,79 +755,99 @@ arm2ir.getCurrentBlock().insertOut(nextInstruction); arm2ir.getCurrentBlock().insertOut(condBlock); + //Query the branch profile to get the probability that this instruction is going to get executed + float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + OPT_BranchProfileOperand profileOperand; + + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); + } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } + else { + profileOperand = OPT_BranchProfileOperand.unlikely(); + } + switch (condition) { case AL: throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); break; case GT: - translateCondition_GT(nextInstruction); + translateCondition_GT(nextInstruction, profileOperand); break; case HI: - translateCondition_HI(nextInstruction); + translateCondition_HI(nextInstruction, profileOperand); break; case LE: - translateCondition_LE(nextInstruction); + translateCondition_LE(nextInstruction, profileOperand); break; case LS: - translateCondition_LS(nextInstruction, condBlock); + translateCondition_LS(nextInstruction, profileOperand, condBlock); break; case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case NV: //never execute this instruction - translateCondition(nextInstruction, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); break; case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); break; default: @@ -839,17 +858,17 @@ conditionalInstruction.translate(); } - private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand operand, OPT_ConditionOperand condition) { - translateCondition(nextInstruction, operand, condition, new OPT_IntConstantOperand(1)); + private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand operand, OPT_ConditionOperand condition) { + translateCondition(nextInstruction, skipProbability, operand, condition, new OPT_IntConstantOperand(1)); } - private void translateCondition(OPT_BasicBlock nextInstruction, OPT_Operand lhs, OPT_ConditionOperand condition, OPT_Operand rhs) { + private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand lhs, OPT_ConditionOperand condition, OPT_Operand rhs) { condition = condition.flipCode(); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), lhs, rhs, condition, nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_HI(OPT_BasicBlock nextInstruction) { + private void translateCondition_HI(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isCarrySet() && !regs.isZeroSet(); OPT_Operand carry = arm2ir.getCarryFlag(); OPT_Operand zero = arm2ir.getZeroFlag(); @@ -858,10 +877,10 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BasicBlock actualInstruction) { + private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); OPT_Operand carry = arm2ir.getCarryFlag(); OPT_Operand zero = arm2ir.getZeroFlag(); @@ -869,7 +888,7 @@ OPT_RegisterOperand result = arm2ir.getTempInt(0); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); /* cond1.deleteNormalOut(); cond1.insertOut(cond2); @@ -885,7 +904,7 @@ cond2.insertOut(actualInstruction);*/ } - private void translateCondition_GT(OPT_BasicBlock nextInstruction) { + private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); OPT_Operand negative = arm2ir.getNegativeFlag(); OPT_Operand overflow = arm2ir.getOverflowFlag(); @@ -895,10 +914,10 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, overflow, OPT_ConditionOperand.NOT_EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } - private void translateCondition_LE(OPT_BasicBlock nextInstruction) { + private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); OPT_Operand negative = arm2ir.getNegativeFlag(); OPT_Operand overflow = arm2ir.getOverflowFlag(); @@ -908,7 +927,7 @@ arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, overflow, OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); } @Override Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-02 12:22:44 UTC (rev 153) @@ -13,6 +13,7 @@ import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; +import org.binarytranslator.Main; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; /** @@ -691,6 +692,7 @@ @Override public void execute() { ps.finished = true; + Main.onExit(0); } } Modified: src/org/binarytranslator/generic/branchprofile/BranchProfile.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/BranchProfile.java 2007-08-02 12:22:44 UTC (rev 153) @@ -121,7 +121,7 @@ throw new IOException("File is not a valid XML branch profile."); int targetAddress = Integer.parseInt(((Element)target).getAttribute("address")); - int branchCount = Integer.parseInt(((Element)target).getAttribute("address")); + int branchCount = Integer.parseInt(((Element)target).getAttribute("branchCount")); targetsAndFrequencies.put(targetAddress, branchCount); } @@ -131,8 +131,6 @@ public void toXML(Document doc, Element parentNode) { Element branchInfo = parentNode; - Element targets = doc.createElement("targets"); - for (Entry<Integer, Integer> branchTarget : destinationsAndFrequencies.entrySet()) { int targetAddress = branchTarget.getKey(); int branchCount = branchTarget.getValue(); @@ -142,8 +140,6 @@ branchTargetElement.setAttribute("address", Integer.toString(targetAddress)); branchTargetElement.setAttribute("branchCount", Integer.toString(branchCount)); } - - branchInfo.appendChild(targets); } } @@ -243,6 +239,33 @@ branchSites.put(origin, branch); } } + + /** + * Returns the probability of a branch from <code>origin</code> to <code>target</code>. + * + * @param origin + * The address at which the branch is taking place. + * @param target + * The address to which the branch is taking place. + * @return + * The probability of the branch as a value between 0 and 1. The function returns -1, if the probability + * cannot be estimated. + */ + public float getBranchProbability(int origin, int target) { + BranchInformation branch = branchSites.get(origin); + + if (branch == null || branch.executionCount == 0) { + return -1f; + } + + Integer branchesToTarget = branch.getTargetsAndFrequencies().get(target); + + if (branchesToTarget == null) { + return 0f; + } + + return branchesToTarget / (float)branch.executionCount; + } /** * Given an address within a procedure, returns the (most likely) procedure @@ -271,7 +294,15 @@ * The address to which it took place. */ public void profileBranch(int origin, int target) { - throw new RuntimeException("Not yet implemented."); + + BranchInformation branch = branchSites.get(origin); + + if (branch == null) { + branch = new BranchInformation(); + branchSites.put(origin, branch); + } + + branch.profile(target); } /** @@ -288,8 +319,21 @@ return (branch == null) ? null : branch.getTargets(); } + /** + * Loads a branch profile from a file. + * + * @param filename + * The name of the file that the branch profile is loaded from. + * @throws IOException + * An exception that is thrown if an error occurs reading that file. + */ public void loadFromXML(String filename) throws IOException { + //clear previous profile data + procedures.clear(); + branchSites.clear(); + + //create a XML document builder and an XML document DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); Document doc; try { @@ -303,34 +347,54 @@ if (DBT.VerifyAssertions) DBT._assert(doc != null); + //Check the root-name of the document Element root = doc.getDocumentElement(); - if (!root.getNodeName().equals("branch-profile")) throw new IOException("File is not a valid XML branch profile."); - Node branches = null; - + //interate over the main document, parsing the different sections for (int i = 0; i < root.getChildNodes().getLength(); i++) { - Node node = root.getChildNodes().item(0); + Node node = root.getChildNodes().item(i); + String nodeName = node.getNodeName(); - if (node.getNodeName().equals("branches")) { - branches = node; - break; + if (node.getNodeType() != Node.ELEMENT_NODE) { + continue; } - } - - if (branches == null) - throw new IOException("File is not a valid XML branch profile."); - - for (int i = 0; i < branches.getChildNodes().getLength(); i++) { - Node siteNode = branches.getChildNodes().item(i); - if (!siteNode.getNodeName().equals("origin") || siteNode.getNodeType() != Node.ELEMENT_NODE) - throw new IOException("File is not a valid XML branch profile."); + if (nodeName.equals("branches")) { - int address = Integer.parseInt(((Element)siteNode).getAttribute("address")); - BranchInformation branchInfo = BranchInformation.fromXML((Element)siteNode); - branchSites.put(address, branchInfo); + //this is the section which contains the branch information. + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node branchNode = node.getChildNodes().item(n); + + if (branchNode.getNodeType() != Node.ELEMENT_NODE) + continue; + + if (!branchNode.getNodeName().equals("branch")) + throw new IOException("File is not a valid XML branch profile."); + + int address = Integer.parseInt(((Element)branchNode).getAttribute("address")); + BranchInformation branchInfo = BranchInformation.fromXML((Element)branchNode); + branchSites.put(address, branchInfo); + } + } + else + if (nodeName.equals("procedures")) { + + //this is the section with procedure information + for (int n = 0; n < node.getChildNodes().getLength(); n++) { + Node procedureInfo = node.getChildNodes().item(n); + + if (procedureInfo.getNodeType() != Node.ELEMENT_NODE) + continue; + + ProcedureInformation pi = ProcedureInformation.fromXML((Element)procedureInfo); + procedures.put(pi.getEntryAddress(), pi); + } + } + else { + throw new IOException("This is not a valid XML branch profile."); + } } } @@ -387,6 +451,15 @@ branchInfo.toXML(doc, branchSiteElement); } + Element proceduresElement = doc.createElement("procedures"); + root.appendChild(proceduresElement); + + for (ProcedureInformation procedure : procedures.values()) { + Element procedureElement = doc.createElement("procedure"); + proceduresElement.appendChild(procedureElement); + procedure.toXML(doc, procedureElement); + } + //Output the resulting XML document TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer; @@ -395,6 +468,7 @@ DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(outputStream); transformer.transform(source, result); + outputStream.close(); } catch (Exception e) { e.printStackTrace(); Modified: src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/CallAndReturnAddress.java 2007-08-02 12:22:44 UTC (rev 153) @@ -12,14 +12,11 @@ * Object for recording a call site and its corresponding return address */ class CallAndReturnAddress { - /** - * Call site address - */ + + /** The address at which the call is taking place.*/ private int callSite; - /** - * Return address - */ + /** The address to which the call shall return. */ private int returnAddress; /** @@ -35,24 +32,29 @@ this.returnAddress = returnAddress; } - /** - * Get call site address - */ + /** Get call site address */ int getCallSite() { return callSite; } - /** - * Get return address - */ + /** Get return address */ int getReturnAddress() { return returnAddress; } + + @Override + public int hashCode() { + return callSite; + } - /** - * Are two call sites the same? - */ + @Override public boolean equals(Object obj) { - return ((CallAndReturnAddress) obj).callSite == callSite; + + if (!(obj instanceof CallAndReturnAddress)) { + return false; + } + + CallAndReturnAddress other = ((CallAndReturnAddress) obj); + return other.callSite == callSite && other.returnAddress == returnAddress; } } Modified: src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java =================================================================== --- src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/branchprofile/ProcedureInformation.java 2007-08-02 12:22:44 UTC (rev 153) @@ -19,20 +19,15 @@ * Objects capturing information about what looks like a method */ class ProcedureInformation { - /** - * Entry point to the procedure - */ + + /** Entry point to the procedure */ private final int entry; - /** - * Set of locations that call the procedure and the corressponding return - * address - */ + /** Set of locations that call the procedure and the corressponding return + * address. */ private HashSet<CallAndReturnAddress> callSitesAndReturnAddresses; - /** - * Set of locations within the procedure that return - */ + /** Set of locations within the procedure that return */ private HashSet<Integer> returnSites; /** @@ -50,8 +45,15 @@ } } - private ProcedureInformation(int entry) { + /** + * Constructor + * + * @param entry + * starting address of the procedure + */ + public ProcedureInformation(int entry) { this.entry = entry; + callSitesAndReturnAddresses = new HashSet<CallAndReturnAddress>(); } /** @@ -64,23 +66,32 @@ * @param returnAddress * the corresponding return address */ - ProcedureInformation(int entry, int callSite, int returnAddress) { - this.entry = entry; - callSitesAndReturnAddresses = new HashSet<CallAndReturnAddress>(); + public ProcedureInformation(int entry, int callSite, int returnAddress) { + this(entry); + callSitesAndReturnAddresses.add(new CallAndReturnAddress(callSite, returnAddress)); } + + /** + * Returns the address at which this procedure starts. + * @return + * The address at which the procedure starts. + */ + public int getEntryAddress() { + return entry; + } /** * Register a call (branch and link) instruction * - * @param pc - * the address of the branch instruction + * @param atAddress + * the address of the call instruction * @param ret * the address that will be returned to */ - public void registerCall(int pc, int ret) { - CallAndReturnAddress call_tuple = new CallAndReturnAddress(pc, ret); + public void registerCall(int atAddress, int ret) { + CallAndReturnAddress call_tuple = new CallAndReturnAddress(atAddress, ret); if (!callSitesAndReturnAddresses.contains(call_tuple)) { callSitesAndReturnAddresses.add(call_tuple); } @@ -89,15 +100,15 @@ /** * Register a return (branch to link register) instruction * - * @param pc + * @param atAddress * the address of the branch instruction */ - public void registerReturn(int pc) { + public void registerReturn(int atAddress) { if (returnSites == null) { returnSites = new HashSet<Integer>(); } - returnSites.add(new Integer(pc)); + returnSites.add(new Integer(atAddress)); } /** @@ -121,13 +132,17 @@ } procedure.appendChild(callSites); - Element returnSites = doc.createElement("returnsites"); - for (Integer returnSite : this.returnSites) { - Element returnSiteNode = doc.createElement("return"); - returnSiteNode.setAttribute("at", returnSite.toString()); - returnSites.appendChild(returnSiteNode); + if (returnSites != null) { + Element returnSitesElement = doc.createElement("returnsites"); + procedure.appendChild(returnSitesElement); + + for (Integer returnSite : returnSites) { + Element returnSiteNode = doc.createElement("return"); + returnSiteNode.setAttribute("at", returnSite.toString()); + returnSitesElement.appendChild(returnSiteNode); + } + } - procedure.appendChild(returnSites); } /** @@ -156,7 +171,7 @@ if (callsite.getNodeType() != Node.ELEMENT_NODE) continue; - if (callsite.getNodeName().equals("call")) + if (!callsite.getNodeName().equals("call")) throw new Error("The given XML node is not a valid ProcedureInformation entity."); int callFrom = Integer.parseInt(((Element)callsite).getAttribute("from")); @@ -166,6 +181,9 @@ } } else if (childNode.getNodeName().equals("returnsites")) { + + pi.returnSites = new HashSet<Integer>(); + //parse return sites for (int n = 0; n < childNode.getChildNodes().getLength(); n++) { Node callsite = childNode.getChildNodes().item(n); @@ -174,7 +192,7 @@ if (callsite.getNodeType() != Node.ELEMENT_NODE) continue; - if (callsite.getNodeName().equals("return")) + if (!callsite.getNodeName().equals("return")) throw new Error("The given XML node is not a valid ProcedureInformation entity."); int returnAt = Integer.parseInt(((Element)callsite).getAttribute("at")); Modified: src/org/binarytranslator/generic/execution/ExecutionController.java =================================================================== --- src/org/binarytranslator/generic/execution/ExecutionController.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/ExecutionController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -9,6 +9,7 @@ Translator, Interpreter, PredecodingInterpreter, + StagedEmulation, GDB } Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -13,23 +13,16 @@ @Override public void run() { Interpreter interpreter = ps.createInterpreter(); - int pc = ps.getCurrentInstructionAddress(); while (!ps.finished) { - Interpreter.Instruction instruction = interpreter.decode(pc); - //System.out.println(String.format("[0x%x] %s", pc, instruction.toString())); - + Interpreter.Instruction instruction = interpreter.decode(pc); instruction.execute(); - //System.out.println(ps.toString()); int nextInstruction = instruction.getSuccessor(pc); if (nextInstruction == -1) { nextInstruction = ps.getCurrentInstructionAddress(); - - if (DBT_Options.profileDuringInterpretation) - ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); } else { ps.setCurrentInstructionAddress(nextInstruction); Modified: src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java =================================================================== --- src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-07-29 13:13:16 UTC (rev 152) +++ src/org/binarytranslator/generic/execution/PredecodingThreadedInterpreter.java 2007-08-02 12:22:44 UTC (rev 153) @@ -8,10 +8,33 @@ import org.binarytranslator.generic.decoder.Interpreter; import org.binarytranslator.generic.os.process.ProcessSpace; +/** + * Execution controller that implements predecoding, threaded interpretation. + * + */ public class PredecodingThreadedInterpreter extends ExecutionController { + /** The controller keeps a cache of commonly used code traces. Each trace is essentially a dynamic basic block. + * This HashMap maps the address of a trace's first instruction to its dynamic basic block. */ private final HashMap<Integer, List<Interpreter.Instruction>> traceCache = new HashMap<Integer, List<Interpreter.Instruction>>(); + + /** The interpreter that is used to perform the actual execution of single instructions. */ private final Interpreter interpreter; + /** Default constructor. */ + public PredecodingThreadedInterpreter(ProcessSpace ps) { + super(ps); + interpreter = ps.createInterpreter(); + } + + /** + * Returns the dynamic basic block of instructions, starting it at address <code>pc</code>. + * This function also manages the trace cache ({@link #traceCache}). + * + * @param pc + * The address at which the dynamic basic block starts. + * @return + * A list of instructions that form the dynamic basic block. + */ private List<Interpreter.Instruction> getTrace(int pc) { List<Interpreter.Instruction> cachedTrace = traceCache.get(pc); @@ -42,6 +65,14 @@ return newTrace; } + /** + * Executes a list of instructions. It is assumed that the first instruction starts at address <code>pc</code>. + * + * @param trace + * The list of instructions that is to be executed. + * @param pc + * The address of the first instruction. + */ protected void executeTrace(List<Interpreter.Instruction> trace, int pc) { Iterator<Interpreter.Instruction> instructions = trace.iterator(); @@ -57,11 +88,6 @@ break; } } - - public PredecodingThreadedInterpreter(ProcessSpace ps) { - super(ps); - interpreter = ps.createInterpreter(); - } @Override public final void run() { Added: src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java (rev 0) +++ src/org/binarytranslator/generic/execution/ProfilingInterpreterController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -0,0 +1,36 @@ +package org.binarytranslator.generic.execution; + +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; + +public class ProfilingInterpreterController extends ExecutionController { + + public ProfilingInterpreterController(ProcessSpace ps) { + super(ps); + } + + @Override + public void run() { + Interpreter interpreter = ps.createInterpreter(); + + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + Interpreter.Instruction instruction = interpreter.decode(pc); + + instruction.execute(); + int nextInstruction = instruction.getSuccessor(pc); + + if (nextInstruction == -1) { + nextInstruction = ps.getCurrentInstructionAddress(); + ps.branchInfo.profileBranch(pc, ps.getCurrentInstructionAddress()); + } + else { + ps.setCurrentInstructionAddress(nextInstruction); + } + + pc = nextInstruction; + } + } + +} Added: src/org/binarytranslator/generic/execution/StagedEmulationController.java =================================================================== --- src/org/binarytranslator/generic/execution/StagedEmulationController.java (rev 0) +++ src/org/binarytranslator/generic/execution/StagedEmulationController.java 2007-08-02 12:22:44 UTC (rev 153) @@ -0,0 +1,121 @@ +package org.binarytranslator.generic.execution; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.os.process.ProcessSpace; +import org.binarytranslator.vmInterface.DBT_Trace; +import org.binarytranslator.vmInterface.DynamicCodeRunner; +import org.jikesrvm.ArchitectureSpecific.VM_CodeArray; + +public class StagedEmulationController extends ExecutionController { + + private final class Trace { + public final List<Interpreter.Instruction> instructions; + public int value; + public DBT_Trace compiledTrace; + + public Trace(List<Interpreter.Instruction> instructions) { + this.instructions = instructions; + value = 0; + } + } + + private final HashMap<Integer, Trace> traceCache = new HashMap<Integer, Trace>(); + private final Interpreter interpreter; + + private Trace getTrace(int pc) { + Trace cachedTrace = traceCache.get(pc); + + if (cachedTrace != null) + return cachedTrace; + + int traceStart = pc; + ArrayList<Interpreter.Instruction> instructions = new ArrayList<Interpreter.Instruction>(5); + + while (true) { + Interpreter.Instruction instruction = interpreter.decode(pc); + pc = instruction.getSuccessor(pc); + instructions.add(instruction); + + //is the successor to this instruction known? + if (pc == -1) { + //No, so stop and create a trace from the decoded instructions + Trace newTrace = new Trace(instructions); + + if (instructions.size() > 3) { + //add this trace to the trace cache, if it contains enough instructions + traceCache.put(traceStart, newTrace); + } + + return newTrace; + } + } + } + + private void compileTrace(Trace trace, int pc) { + if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace == null); + + trace.compiledTrace = new DBT_Trace(ps, pc); + trace.compiledTrace.compile(); + } + + private void executeTrace(Trace trace, int pc) { + + //check if the trace is being executed very frequently... + if (trace.value > 20) { + + if (DBT_Options.debugTranslation) + System.out.println("Switching to interpretation at address 0x" + Integer.toHexString(pc)); + + //yes, so we should rather try to execute a translated version + if (trace.compiledTrace == null) { + //compile the trace, if necessary + compileTrace(trace, pc); + if (DBT.VerifyAssertions) DBT._assert(trace.compiledTrace != null); + } + + //execute the trace + VM_CodeArray code = trace.compiledTrace.getCurrentCompiledMethod().getEntryCodeArray(); + ps.setCurrentInstructionAddress(DynamicCodeRunner.invokeCode(code, ps)); + } + else { + trace.value += trace.instructions.size(); + } + + Iterator<Interpreter.Instruction> instructions = trace.instructions.iterator(); + while (true) { + Interpreter.Instruction instr = instructions.next(); + instr.execute(); + + if (instructions.hasNext()) { + pc = instr.getSuccessor(pc); + ps.setCurrentInstructionAddress(pc); + } + else + break; + } + } + + public StagedEmulationController(ProcessSpace ps) { + super(ps); + interpreter = ps.createInterpreter(); + } + + @Override + public void run() { + int pc = ps.getCurrentInstructionAddress(); + + while (!ps.finished) { + + Trace trace = getTrace(pc); + executeTrace(trace, pc); + pc = ps.getCurrentInstructionAddress(); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-07 22:28:52
|
Revision: 161 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=161&view=rev Author: michael_baer Date: 2007-08-07 15:28:53 -0700 (Tue, 07 Aug 2007) Log Message: ----------- - Added support for interchangeable flag behaviour and flag laziness on ARM - Improved usage of profiling data for conditional instructions on ARM Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/vmInterface/DBT_Trace.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/DBT_Options.java 2007-08-07 22:28:53 UTC (rev 161) @@ -93,9 +93,12 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information.. */ + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information. */ public static boolean optimizeTranslationByProfiling = false; + /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using lazy evaluation.*/ + public static boolean optimizeTranslationByLazyEvaluation = true; + /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -179,6 +182,8 @@ debugSyscall = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugSyscallMore")) { debugSyscallMore = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugTranslation")) { + debugTranslation = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (key.equalsIgnoreCase("instrOpt1")) { @@ -201,9 +206,12 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); - } else if (key.equalsIgnoreCase("optimizeTranslation")) { + } else if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("optimizeByLazy")) { + optimizeTranslationByLazyEvaluation = Boolean.parseBoolean(value); } + else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:28:53 UTC (rev 161) @@ -3,6 +3,9 @@ import java.util.ArrayList; import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Flag; +import org.binarytranslator.arch.arm.decoder.ARM_Laziness.Operation; import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; @@ -77,6 +80,9 @@ /** The class performing the actual translation of the bytecode. */ private final ARM_Translator translator; + /** Determines how flags are resolved and if laziness is used.*/ + private final ARM_FlagBehavior flagBehavior; + static { psTref = VM_TypeReference.findOrCreate(ARM_ProcessSpace.class); @@ -136,8 +142,274 @@ public ARM2IR(OPT_GenerationContext context, DBT_Trace trace) { super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); + + if (DBT_Options.optimizeTranslationByLazyEvaluation) + flagBehavior = new ARM_LazyFlagBehavior(); + else + flagBehavior = new ARM_ImmediateFlagBehavior(); } + + /** ARM has an interchangeable flag behavior. Flags can either be evaluated immediately or on demand using + * lazy evaluation. This interface encapsulates the differences. */ + public abstract class ARM_FlagBehavior { + + /** + * Interface helper function. If a flag behaviour wants to set a value of a flag, it shall set + * the {@link OPT_RegisterOperand} returned by this function. + */ + protected final OPT_RegisterOperand getFlag(Flag flag) { + switch (flag) { + case Zero: + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + + case Carry: + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + + case Negative: + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + + case Overflow: + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + + default: + throw new RuntimeException("Unexpected flag type: " + flag); + } + } + /** Called before a flag is written to directly. */ + public abstract void onFlagWrite(Flag flag, ARM_Laziness lazy); + + /** Called before a flag is read. */ + public abstract void onFlagRead(Flag flag, ARM_Laziness lazy); + + /** Called when the ARM flags shall be set by a logical operation. This sets the zero and negative flag. */ + public abstract void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result); + + /** Called when the ARM flags shall be set by a ADD operation. This sets all ARM flags. */ + public abstract void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + + /** Called when the ARM flags shall be set by a SUB operation. This sets all ARM flags. */ + public abstract void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2); + } + + /** Implements a flag behavior that will immediately evaluate all flag values. */ + public final class ARM_ImmediateFlagBehavior extends ARM_FlagBehavior { + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Zero), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Negative), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + //nothing to do here, because the flags are already resolved + } + } + + /** Implements a flag behavior that will use lazy evaluation to only determine a flag value + * when it is necessary. */ + public final class ARM_LazyFlagBehavior extends ARM_FlagBehavior { + + /** Operands for lazy evaluation of condition codes. */ + private OPT_Register lazyOperand1; + private OPT_Register lazyOperand2; + private OPT_Register lazyLogicalOperand; + + public ARM_LazyFlagBehavior() { + //prepare the laziness registers + lazyOperand1 = makeTemp(VM_TypeReference.Int).register; + lazyOperand2 = makeTemp(VM_TypeReference.Int).register; + lazyLogicalOperand = makeTemp(VM_TypeReference.Int).register; + } + + @Override + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Add); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int), result.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + + switch (lazy.getOperation()) { + case Add: + lazy.setOperation(Operation.LogicalOpAfterAdd); + break; + + case Sub: + lazy.setOperation(Operation.LogicalOpAfterSub); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int), op1.copy())); + appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int), op2.copy())); + + lazy.setValid(Flag.Zero, false); + lazy.setValid(Flag.Negative, false); + lazy.setValid(Flag.Carry, false); + lazy.setValid(Flag.Overflow, false); + lazy.setOperation(Operation.Sub); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + private void resolveFlag(ARM_Laziness.Flag flag, ARM_Laziness lazy) { + + if (lazy.isValid(flag)) + return; + + if (DBT_Options.debugTranslation) { + System.out.println("Resolving " + flag + " flag."); + } + + OPT_RegisterOperand flagRegister = getFlag(flag); + OPT_RegisterOperand op1 = new OPT_RegisterOperand(lazyOperand1, VM_TypeReference.Int); + OPT_RegisterOperand op2 = new OPT_RegisterOperand(lazyOperand2, VM_TypeReference.Int); + OPT_RegisterOperand result; + + switch (lazy.getOperation()) { + case Add: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_ADD, result, op1, op2)); + break; + + case Sub: + result = gc.temps.makeTempInt(); + appendInstruction(Binary.create(INT_SUB, result, op1, op2)); + break; + + case LogicalOpAfterAdd: + case LogicalOpAfterSub: + result = new OPT_RegisterOperand(lazyLogicalOperand, VM_TypeReference.Int); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + switch (flag) { + case Zero: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + break; + + case Carry: + switch (lazy.getOperation()) { + case LogicalOpAfterAdd: + case Add: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), op1.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); + break; + + case LogicalOpAfterSub: + case Sub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + break; + + case Negative: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + break; + + case Overflow: + switch (lazy.getOperation()) { + case Add: + case LogicalOpAfterAdd: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + break; + + case Sub: + case LogicalOpAfterSub: + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); + break; + + default: + throw new RuntimeException("Unhandled laziness operation: " + lazy.getOperation()); + } + + break; + + default: + throw new RuntimeException("Unhandled flag type: " + flag); + } + + lazy.setValid(flag, true); + + if (DBT_Options.debugTranslation) { + System.out.println("New Lazy state: " + lazy); + } + } + + @Override + public void onFlagRead(Flag flag, ARM_Laziness lazy) { + resolveFlag(flag, lazy); + + } + + @Override + public void onFlagWrite(Flag flag, ARM_Laziness lazy) { + lazy.setValid(flag, true); + } + } + @Override protected Laziness createInitialLaziness() { return new ARM_Laziness(); @@ -319,26 +591,67 @@ return new OPT_RegisterOperand(regMap[r], VM_TypeReference.Int); } - public OPT_RegisterOperand getCarryFlag() { + public OPT_Operand readCarryFlag(ARM_Laziness lazy) { carryUsed = true; + flagBehavior.onFlagRead(Flag.Carry, lazy); return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getZeroFlag() { + public OPT_Operand readZeroFlag(ARM_Laziness lazy) { zeroUsed = true; + flagBehavior.onFlagRead(Flag.Zero, lazy); return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getNegativeFlag() { + public OPT_Operand readNegativeFlag(ARM_Laziness lazy) { negativeUsed = true; + flagBehavior.onFlagRead(Flag.Negative, lazy); return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); } - public OPT_RegisterOperand getOverflowFlag() { + public OPT_Operand readOverflowFlag(ARM_Laziness lazy) { overflowUsed = true; + flagBehavior.onFlagRead(Flag.Overflow, lazy); return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); } + public OPT_RegisterOperand writeCarryFlag(ARM_Laziness lazy) { + carryUsed = true; + flagBehavior.onFlagWrite(Flag.Carry, lazy); + return new OPT_RegisterOperand(carryFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeZeroFlag(ARM_Laziness lazy) { + zeroUsed = true; + flagBehavior.onFlagWrite(Flag.Zero, lazy); + return new OPT_RegisterOperand(zeroFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeNegativeFlag(ARM_Laziness lazy) { + negativeUsed = true; + flagBehavior.onFlagWrite(Flag.Negative, lazy); + return new OPT_RegisterOperand(negativeFlag, VM_TypeReference.Boolean); + } + + public OPT_RegisterOperand writeOverflowFlag(ARM_Laziness lazy) { + overflowUsed = true; + flagBehavior.onFlagWrite(Flag.Overflow, lazy); + return new OPT_RegisterOperand(overflowFlag, VM_TypeReference.Boolean); + } + + public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + flagBehavior.appendLogicalFlags(lazy, result); + } + + public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendSubFlags(lazy, result, op1, op2); + } + + public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + flagBehavior.appendAddFlags(lazy, result, op1, op2); + } + + @Override protected OPT_Register[] getUnusedRegisters() { @@ -372,7 +685,19 @@ @Override public void resolveLaziness(Laziness laziness) { - //NO-OP, as we're not using laziness at the moment + ARM_Laziness lazy = (ARM_Laziness)laziness; + + if (carryUsed) + flagBehavior.onFlagRead(Flag.Carry, lazy); + + if (negativeUsed) + flagBehavior.onFlagRead(Flag.Negative, lazy); + + if (overflowUsed) + flagBehavior.onFlagRead(Flag.Overflow, lazy); + + if (zeroUsed) + flagBehavior.onFlagRead(Flag.Zero, lazy); } @Override Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Disassembler.java 2007-08-07 22:28:53 UTC (rev 161) @@ -46,13 +46,18 @@ Instruction decodedInstruction; - if ((address & 0x1) == 1) { - short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); - decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + try { + if ((address & 0x1) == 1) { + short binaryInstruction = (short)ps.memory.loadInstruction16(address & 0xFFFFFFFE); + decodedInstruction = ARM_InstructionDecoder.Thumb.decode(binaryInstruction); + } + else { + int binaryInstruction = ps.memory.loadInstruction32(address); + decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + } } - else { - int binaryInstruction = ps.memory.loadInstruction32(address); - decodedInstruction = ARM_InstructionDecoder.ARM32.decode(binaryInstruction); + catch (Exception e) { + return new ARM_DisassembledInstruction("Exception (" + e + ") while reading instruction at 0x" + Integer.toHexString(address)); } DisassemblingVisitor disassembler = new DisassemblingVisitor(); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:28:53 UTC (rev 161) @@ -2,41 +2,115 @@ import org.binarytranslator.generic.decoder.Laziness; -public class ARM_Laziness extends Laziness { +public final class ARM_Laziness extends Laziness { + public enum Operation { + Add, Sub, LogicalOpAfterAdd, LogicalOpAfterSub + } + + public enum Flag { + Carry, Zero, Negative, Overflow + } + + /** The state of the different ARM flags, compressed as bit fields within an integer. */ + private int flagValid; + + /** The operation that has to be performed to evaluate the remaining registers */ + private Operation lazinessOperation; + final class ARM_LazinessKey extends Key { private final int pc; + private final byte flagState; public int hashCode() { - return pc; + return pc | flagState; } public boolean equals(Object o) { - return ((o instanceof ARM_LazinessKey) && ((ARM_LazinessKey) o).pc == pc); + if (!(o instanceof ARM_LazinessKey)) + return false; + + ARM_LazinessKey otherKey = (ARM_LazinessKey)o; + return otherKey.pc == pc && otherKey.flagState == flagState; } - ARM_LazinessKey(int pc) { + ARM_LazinessKey(int pc, ARM_Laziness lazy) { this.pc = pc; + int tmpFlagState = lazy.flagValid & 0xF; + tmpFlagState |= (lazinessOperation.ordinal() + 1) << 4; + + this.flagState = (byte)tmpFlagState; } public String toString() { - return "0x" + Integer.toHexString(pc); + return String.format("0x%x (%d)", pc, flagState); } } + public ARM_Laziness() { + flagValid = 0xF; //all flags are valid + lazinessOperation = Operation.Add; + } + + private ARM_Laziness(ARM_Laziness other) { + set(other); + } + + public void setValid(Flag flag, boolean valid) { + flagValid |= 1 << flag.ordinal(); + } + + public boolean isValid(Flag flag) { + return (flagValid & (1 << flag.ordinal())) != 0; + } + + public void setAddOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Add; + } + + public void setSubOperation() { + flagValid = 0; // all flags are invalid + lazinessOperation = Operation.Sub; + } + + public Operation getOperation() { + return lazinessOperation; + } + + public void setOperation(Operation lazinessOperation) { + this.lazinessOperation = lazinessOperation; + } + + public void set(ARM_Laziness other) { + flagValid = other.flagValid; + lazinessOperation = other.lazinessOperation; + } + @Override public Object clone() { - return new ARM_Laziness(); + return new ARM_Laziness(this); } @Override - public boolean equivalent(Laziness other) { - return other instanceof ARM_Laziness; + public boolean equivalent(Laziness o) { + if (!(o instanceof ARM_Laziness)) + return false; + + ARM_Laziness other = (ARM_Laziness)o; + return flagValid == other.flagValid && lazinessOperation == other.lazinessOperation; } @Override public Key makeKey(int pc) { - return new ARM_LazinessKey(pc); + return new ARM_LazinessKey(pc, this); } + @Override + public String toString() { + return "Operation: " + lazinessOperation + ", C:" + (isValid(Flag.Carry) ? "1" : "0") + + ", Z:" + (isValid(Flag.Zero) ? "1" : "0") + + ", N:" + (isValid(Flag.Negative) ? "1" : "0") + + ", O:" + (isValid(Flag.Overflow) ? "1" : "0"); + } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -377,8 +377,9 @@ curBlock.deleteNormalOut(); curBlock.insertOut(nextBlock); curBlock.insertOut(block1); + OPT_Operand carryFlag = translator.arm2ir.readCarryFlag(translator.lazy); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -414,7 +415,7 @@ value = new OPT_IntConstantOperand(operand.getImmediate()); if (operand.getShiftAmount() != 0) { - OPT_RegisterOperand carryFlag = translator.arm2ir.getCarryFlag(); + OPT_RegisterOperand carryFlag = translator.arm2ir.writeCarryFlag(translator.lazy); OPT_Operand shifterCarryOut = new OPT_IntConstantOperand(((operand.getImmediate() & 0x80000000) != 0) ? 1 : 0); //otherwise there is no shifter carry out @@ -451,7 +452,7 @@ /** Returns the register that receives the shifte carry out*/ private OPT_RegisterOperand getShifterCarryOutTarget() { - return translator.arm2ir.getCarryFlag(); + return translator.arm2ir.writeCarryFlag(translator.lazy); } /** @@ -685,7 +686,7 @@ curBlock.insertOut(block1); curBlock.insertOut(nextBlock); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, translator.arm2ir.readCarryFlag(translator.lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -720,7 +721,7 @@ /** Return the instruction following this one or -1, if that is not yet known. */ int getSuccessor(int pc); } - + /** All ARM instructions that are supposed to be executed conditionally * are decorated with this decorator. * The decorator takes care of checking the individual condition and depending on it, executing the @@ -729,7 +730,7 @@ protected final ARM_Instruction conditionalInstruction; protected final Condition condition; - + /** Decorates an ARM interpreter instruction, by making it execute conditionally. */ protected ConditionalDecorator(ARM_Instruction i) { conditionalInstruction = i; @@ -738,132 +739,213 @@ public int getSuccessor(int pc) { - boolean thumbMode = (pc & 0x1) == 1; - return pc + (thumbMode ? 2 : 4); + if (assumeInstructionWillBeSkipped()) { + boolean thumbMode = (pc & 0x1) == 1; + return pc + (thumbMode ? 2 : 4); + } + else { + return conditionalInstruction.getSuccessor(pc); + } } public Condition getCondition() { return condition; } + /** + * Returns the probability that this conditional instruction will be skipped. + * + * @return + * The probability that this conditional instruction will be skipped. Returns -1, if this probability + * cannot be estimated. + */ + private float getSkipProbability() { + + if (DBT_Options.optimizeTranslationByProfiling) + return -1f; + + return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + } + + /** + * During the processing of this conditional instruction, shall we assume that it will be skipped? + * This is helpful to optimize the trace. + * + * @return + * True if it is likely that this instruction will be skipped. False otherwise. + */ + private boolean assumeInstructionWillBeSkipped() { + float skipProbability = getSkipProbability(); + + return (skipProbability == -1f || skipProbability > 0.5f); + } + + /** + conditionals are implemented easily: if the condition does not hold, then just + jump to the block following the conditional instruction. To do this, the following structure of + block is built: + + -------------------------------------------------------- + 1. block that checks the condition + -------------------------------------------------------- + 2. conditional instruction + -------------------------------------------------------- + 3. next instruction, when the instruction was not skipped + -------------------------------------------------------- + 4. next instruction, when it was skipped <- next block + -------------------------------------------------------- + + Note that the two last blocks are only necessary when laziness is used. Otherwise, the first of + them will remain empty. + */ public void translate() { - //conditionals are implemented easily: if the condition does not hold, then just - //jump to the block following the conditional instruction - OPT_BasicBlock nextInstruction = arm2ir.getNextBlock(); - OPT_BasicBlock condBlock = arm2ir.createBlockAfterCurrent(); - arm2ir.getCurrentBlock().deleteNormalOut(); - arm2ir.getCurrentBlock().insertOut(nextInstruction); - arm2ir.getCurrentBlock().insertOut(condBlock); + + OPT_BasicBlock blockThatChecksCondition = arm2ir.getCurrentBlock(); + OPT_BasicBlock nextInstruction_InstructionSkipped = arm2ir.getNextBlock(); + OPT_BasicBlock nextInstruction_InstructionNotSkipped = arm2ir.createBlockAfterCurrent(); + OPT_BasicBlock condInstructionBlock = arm2ir.createBlockAfterCurrent(); + + //prepare to translate the actual condition + arm2ir.setCurrentBlock(blockThatChecksCondition); + blockThatChecksCondition.deleteNormalOut(); + blockThatChecksCondition.insertOut(nextInstruction_InstructionSkipped); + blockThatChecksCondition.insertOut(condInstructionBlock); //Query the branch profile to get the probability that this instruction is going to get executed OPT_BranchProfileOperand profileOperand; - if (DBT_Options.optimizeTranslationByProfiling) { - float skipProbability = ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); + float skipProbability = getSkipProbability(); - if (skipProbability == -1 || skipProbability == 0.5f) { - profileOperand = new OPT_BranchProfileOperand(); - } - else if (skipProbability > 0.8f) { - profileOperand = OPT_BranchProfileOperand.always(); - condBlock.setInfrequent(); - } - else if (skipProbability > 0.5f) { - profileOperand = OPT_BranchProfileOperand.likely(); - condBlock.setInfrequent(); - } - else if (skipProbability < 0.2f) { - profileOperand = OPT_BranchProfileOperand.never(); - } - else { - profileOperand = OPT_BranchProfileOperand.unlikely(); - } + if (skipProbability == -1 || skipProbability == 0.5f) { + profileOperand = new OPT_BranchProfileOperand(); } + else if (skipProbability > 0.8f) { + profileOperand = OPT_BranchProfileOperand.always(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability > 0.5f) { + profileOperand = OPT_BranchProfileOperand.likely(); + condInstructionBlock.setInfrequent(); + } + else if (skipProbability < 0.2f) { + profileOperand = OPT_BranchProfileOperand.never(); + } else { - profileOperand = new OPT_BranchProfileOperand(); + profileOperand = OPT_BranchProfileOperand.unlikely(); } switch (condition) { case AL: - throw new RuntimeException("ARM32 instructions with a condition of AL (always) should not be decorated with a ConditionalDecorator."); + throw new RuntimeException("Unconditional instructions should not be decorated with a ConditionalDecorator."); case CC: //return !regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case CS: //return regs.isCarrySet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getCarryFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readCarryFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case EQ: //return regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case GE: //return regs.isNegativeSet() == regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case GT: - translateCondition_GT(nextInstruction, profileOperand); + translateCondition_GT(nextInstruction_InstructionSkipped, profileOperand); break; case HI: - translateCondition_HI(nextInstruction, profileOperand); + translateCondition_HI(nextInstruction_InstructionSkipped, profileOperand); break; case LE: - translateCondition_LE(nextInstruction, profileOperand); + translateCondition_LE(nextInstruction_InstructionSkipped, profileOperand); break; case LS: - translateCondition_LS(nextInstruction, profileOperand, condBlock); + translateCondition_LS(nextInstruction_InstructionSkipped, profileOperand, condInstructionBlock); break; case LT: //return regs.isNegativeSet() != regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.getOverflowFlag()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL(), arm2ir.readOverflowFlag(lazy)); break; case MI: //return regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.EQUAL()); break; case NE: //return !regs.isZeroSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getZeroFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readZeroFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case NV: //never execute this instruction - translateCondition(nextInstruction, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL()); break; case PL: //return !regs.isNegativeSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getNegativeFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readNegativeFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VC: //return !regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.NOT_EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.NOT_EQUAL()); break; case VS: //return regs.isOverflowSet(); - translateCondition(nextInstruction, profileOperand, arm2ir.getOverflowFlag(), OPT_ConditionOperand.EQUAL()); + translateCondition(nextInstruction_InstructionSkipped, profileOperand, arm2ir.readOverflowFlag(lazy), OPT_ConditionOperand.EQUAL()); break; default: throw new RuntimeException("Unexpected condition code: " + condition); - } + } + + //Translate the conditional instruction first to see if the lazy state is changed by the + //conditional instruction + ARM_Laziness lazinessWhenInstructionSkipped = (ARM_Laziness)lazy.clone(); - arm2ir.setCurrentBlock(condBlock); + arm2ir.setCurrentBlock(condInstructionBlock); + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); conditionalInstruction.translate(); + + int followingInstructionAddress = pc + (inThumb() ? 2 : 4); + + //yes it did, so we may need to translate the successor instruction twice + if (assumeInstructionWillBeSkipped()) { + + //Did the laziness change during the translation? + if (!lazy.equivalent(lazinessWhenInstructionSkipped)) { + //Modify block 3 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionNotSkipped); + nextInstruction_InstructionNotSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazy); + lazy.set(lazinessWhenInstructionSkipped); + } + + arm2ir.setNextBlock(nextInstruction_InstructionSkipped); + + } + else { + //Modify block 4 so that it resolves the different laziness correctly + arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); + nextInstruction_InstructionSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); + + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + } } private void translateCondition(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_Operand operand, OPT_ConditionOperand condition) { @@ -878,8 +960,8 @@ private void translateCondition_HI(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isCarrySet() && !regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, carry, @@ -890,33 +972,20 @@ private void translateCondition_LS(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability, OPT_BasicBlock actualInstruction) { //return !regs.isCarrySet() || regs.isZeroSet(); - OPT_Operand carry = arm2ir.getCarryFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand carry = arm2ir.readCarryFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getTempInt(0); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, carry, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand(), zero, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), result.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), nextInstruction.makeJumpTarget(), skipProbability)); - -/* cond1.deleteNormalOut(); - cond1.insertOut(cond2); - cond1.insertOut(actualInstruction); - - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), carry, new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - - arm2ir.setCurrentBlock(cond2); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), zero, new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), actualInstruction.makeJumpTarget(), new OPT_BranchProfileOperand())); - arm2ir.appendInstruction(Goto.create(GOTO, nextInstruction.makeJumpTarget())); - cond2.deleteNormalOut(); - cond2.insertOut(nextInstruction); - cond2.insertOut(actualInstruction);*/ } private void translateCondition_GT(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_OR, result, negative, @@ -927,9 +996,9 @@ private void translateCondition_LE(OPT_BasicBlock nextInstruction, OPT_BranchProfileOperand skipProbability) { //return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); - OPT_Operand negative = arm2ir.getNegativeFlag(); - OPT_Operand overflow = arm2ir.getOverflowFlag(); - OPT_Operand zero = arm2ir.getZeroFlag(); + OPT_Operand negative = arm2ir.readNegativeFlag(lazy); + OPT_Operand overflow = arm2ir.readOverflowFlag(lazy); + OPT_Operand zero = arm2ir.readZeroFlag(lazy); OPT_RegisterOperand result = arm2ir.getGenerationContext().temps.makeTempBoolean(); arm2ir.appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, result, negative, @@ -1021,21 +1090,8 @@ * The add's right-hand-side operator. */ protected final void setAddFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), result.copy(), lhs.copy(), OPT_ConditionOperand.LOWER(), new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendAddFlags(lazy, result, lhs, rhs); } /** Sets the processor flags according to the result of subtracting <code>rhs</code> from <code>lhs</code>.*/ @@ -1077,22 +1133,8 @@ * The sub's right-hand-side operator. */ protected final void setSubFlags(OPT_Operand result, OPT_Operand lhs, OPT_Operand rhs) { - //set the carry flag to not(Borrow) - OPT_ConditionOperand notBorrowFromSub = OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(); - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getCarryFlag(), lhs.copy(), rhs.copy(), notBorrowFromSub, new OPT_BranchProfileOperand())); - //set the overflow flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getOverflowFlag(), lhs.copy(), rhs.copy(), OPT_ConditionOperand.OVERFLOW_FROM_SUB(), OPT_BranchProfileOperand.unlikely())); - - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + arm2ir.appendSubFlags(lazy, result, lhs, rhs); } public Condition getCondition() { @@ -1165,13 +1207,8 @@ protected final void setLogicalFlags(OPT_Operand result) { //the shifter carry out has already been set during the resolve-phase - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -1287,7 +1324,7 @@ //Is the carry set at all? if not, just jump to addWithoutCarry arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. @@ -1318,7 +1355,7 @@ //Is the carry set? if yes, just jump to subWithoutCarry arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.getCarryFlag(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); + arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(subWithCarry); //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). @@ -1674,41 +1711,7 @@ //first translate the register write back translateWriteback(startAddress.copyRO(), nextAddress.copyRO()); - - //shall we switch to thumb mode? - /*OPT_BasicBlock finishInstruction = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToARMBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - OPT_BasicBlock switchToThumbBlock = arm2ir.createBlockAfterCurrentNotInCFG(); - - //Current block - OPT_BasicBlock currentBlock = arm2ir.getCurrentBlock(); - currentBlock.deleteNormalOut(); - currentBlock.insertOut(switchToARMBlock); - currentBlock.insertOut(switchToThumbBlock); - arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), regPC.copy(), new OPT_IntConstantOperand(1), OPT_ConditionOperand.BIT_TEST(), switchToThumbBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); - arm2ir.appendInstruction(Goto.create(GOTO, switchToARMBlock.makeJumpTarget())); - - //Yes, switch to thumb mode - arm2ir.setCurrentBlock(switchToThumbBlock); - switchToThumbBlock.insertOut(finishInstruction); - OPT_Instruction call_setThumbMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setThumbMode, 1, new OPT_IntConstantOperand(1)); - arm2ir.appendCustomCall(call_setThumbMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - //No, don't switch to thumb mode - arm2ir.setCurrentBlock(switchToARMBlock); - switchToARMBlock.insertOut(finishInstruction); - arm2ir.appendInstruction(Binary.create(INT_AND, regPC.copyRO(), regPC.copy(), new OPT_IntConstantOperand(0xFFFFFFFE))); - OPT_Instruction call_setArmMode = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(call_setArmMode, 1, new OPT_IntConstantOperand(0)); - arm2ir.appendCustomCall(call_setArmMode); - arm2ir.appendInstruction(Goto.create(GOTO, finishInstruction.makeJumpTarget())); - - //according to the APCS, these types of instructions are usually function returns - arm2ir.setCurrentBlock(finishInstruction); - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN);*/ - arm2ir.appendBranch(regPC, lazy, BranchType.RETURN); return; } @@ -1940,13 +1943,8 @@ } if (i.updateConditionCodes) { - //set the negative flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getNegativeFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); - - //set the zero flag - arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_INT, arm2ir.getZeroFlag(), result.copyRO(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + //set the negative & zero flag + arm2ir.appendLogicalFlags(lazy, result); } } @@ -2006,13 +2004,13 @@ } if (i.updateConditionCodes) { - //set the negative flag + //set the negative flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getNegativeFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeNegativeFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS(), new OPT_BranchProfileOperand())); //set the zero flag arm2ir.appendInstruction(BooleanCmp.create( - BOOLEAN_CMP_LONG, arm2ir.getZeroFlag(), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); + BOOLEAN_CMP_LONG, arm2ir.writeZeroFlag(lazy), result.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), new OPT_BranchProfileOperand())); } } @@ -2223,6 +2221,7 @@ //do we actually have to perform the rotation? arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), rotation.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.NOT_EQUAL(), rotationBlock.makeJumpTarget(), OPT_BranchProfileOperand.never())); arm2ir.appendInstruction(Goto.create(GOTO, remainderBlock.makeJumpTarget())); + arm2ir.getCurrentBlock().insertOut(remainderBlock); //in case we are performing the rotation... arm2ir.setCurrentBlock(rotationBlock); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:28:53 UTC (rev 161) @@ -247,7 +247,7 @@ * dependencies (unknown branch targets etc.) have been resolved. This function is useful for * debug purposes. */ - protected void printTraceAfterCompletion() { + public void printTraceAfterCompletion() { printTraceAfterCompletionRequested = true; } @@ -283,18 +283,9 @@ printTraceAfterCompletionRequested = false; printNextBlocks(preFillBlock, 50); } + + ((DBT_Trace) gc.method).setNumberOfInstructions(numberOfInstructions); } - /* - protected final void maximizeBasicBlocks(OPT_IR ir) { - for (OPT_BasicBlock currBB = ir.cfg.firstInCodeOrder(); currBB != null;) { - if (currBB.mergeFallThrough(ir)) { - // don't advance currBB; it may have a new trivial fallthrough to - // swallow - } else { - currBB = currBB.nextBasicBlockInCodeOrder(); - } - } - }*/ /** @@ -759,8 +750,11 @@ * within the code cache c) The trace is already too long d) the branch is * supposedly a CALL or RETURN */ + + DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + return DBT_Options.singleInstrTranslation == false - && ps.codeCache.tryGet(targetPc) == null && !shallTraceStop() + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 20) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; } @@ -789,7 +783,7 @@ if (targetBB != null) return targetBB; - if (inlineBranchInstruction(targetPc, jump)) { + if (!inlineBranchInstruction(targetPc, jump)) { // Just exit the trace and continue at the target address in a new trace if (currentBlock.getNumberOfRealInstructions() != 0) { @@ -903,7 +897,7 @@ // Copy the value into the register specified by gc.resultReg. appendInstruction(Move.create(INT_MOVE, new OPT_RegisterOperand( gc.resultReg, VM_TypeReference.Int), nextPc.copy())); - resolveLaziness(laziness); + resolveLaziness((Laziness)laziness.clone()); appendInstruction(Goto.create(GOTO, finishBlock.makeJumpTarget())); currentBlock.deleteNormalOut(); currentBlock.insertOut(finishBlock); @@ -1305,9 +1299,7 @@ */ public void appendInterpretedInstruction(int pc, Laziness lazy) { - if (lazy != null) - resolveLaziness(lazy); - + resolveLaziness(lazy); spillAllRegisters(); // Prepare a local variable of type Interpreter Modified: src/org/binarytranslator/vmInterface/DBT_Trace.java =================================================================== --- src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:27:33 UTC (rev 160) +++ src/org/binarytranslator/vmInterface/DBT_Trace.java 2007-08-07 22:28:53 UTC (rev 161) @@ -97,6 +97,9 @@ */ public final int pc; + /** The number of guest instructions that have been compiled into this trace. */ + private int numberOfInstructions; + /** * In order to allow arbitrary calls within a trace, we have to store at which bytecode index * a method is called in which way. This class stores the necessary information. */ @@ -321,4 +324,12 @@ public int getBytecodeLength() { return 256; } + + public int getNumberOfInstructions() { + return numberOfInstructions; + } + + public void setNumberOfInstructions(int numberOfInstructions) { + this.numberOfInstructions = numberOfInstructions; + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-08 10:22:43
|
Revision: 162 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=162&view=rev Author: michael_baer Date: 2007-08-08 03:22:45 -0700 (Wed, 08 Aug 2007) Log Message: ----------- - Compress flag state into a single integer in ARM_Laziness - Setting blocks as infrequent using profiling information - Move some platform-specific command line options to DBT_Options Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/DBT_Options.java 2007-08-08 10:22:45 UTC (rev 162) @@ -13,6 +13,7 @@ import java.util.Map; import java.util.Map.Entry; +import org.binarytranslator.arch.arm.decoder.ARM_Options; import org.binarytranslator.generic.execution.ExecutionController; /** @@ -93,12 +94,6 @@ /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ public static int minTraceValue = 20; - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using profiling information. */ - public static boolean optimizeTranslationByProfiling = false; - - /** Just a temporary variable for testing. It describes, if the translated program shall be optimized using lazy evaluation.*/ - public static boolean optimizeTranslationByLazyEvaluation = true; - /** Print debug information during the translation of instructions. */ public static boolean debugTranslation = true; @@ -122,7 +117,7 @@ /** Stores the arguments given to the DBT by the user. These are NOT the arguments given to the executable. */ private static HashMap<String, String> dbtArguments = null; - + /** Read and parse the command line arguments. */ public static void parseArguments(String[] args) { @@ -150,7 +145,7 @@ String value = argument.getValue(); try { - parseSingleArgument(arg, value); + parseSingleOption(arg, value); } catch (NumberFormatException e) { throw new Error("Argument " + arg + " is not a valid integer."); @@ -162,14 +157,40 @@ } /** Parses a single argument into the options class. */ - private static void parseSingleArgument(String key, String value) { + private static void parseSingleOption(String key, String value) { - if (!key.startsWith("-X:dbt:")) { - throw new Error("Invalid argument. Argument prefix '-X:dbt:' expected."); + if (!key.startsWith("-X:")) { + throw new Error("Invalid argument. Argument prefix '-X:' expected."); } - key = key.substring(7); + key = key.substring(3); + + if (key.startsWith("dbt:")) { + key = key.substring(4); + + parseDbtOption(key, value); + } + else if (key.startsWith("arm:")) { + key = key.substring(4); + parseArmOption(key, value); + } + else { + throw new Error("Unknown argument."); + } + } + + private static void parseArmOption(String key, String value) { + if (key.equalsIgnoreCase("optimizeByProfiling")) { + ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("flagBehaviour")) { + ARM_Options.flagBehaviour = ARM_Options.FlagBehaviour.valueOf(value); + } + else { + throw new Error("Unknown ARM option: " + key); + } + } + private static void parseDbtOption(String key, String value) { if (key.equalsIgnoreCase("debugInstr")) { debugInstr = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugRuntime")) { @@ -206,12 +227,7 @@ saveProfileToFile = value; } else if (key.equalsIgnoreCase("minTraceValue")) { minTraceValue = Integer.parseInt(value); - } else if (key.equalsIgnoreCase("optimizeByProfiling")) { - optimizeTranslationByProfiling = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("optimizeByLazy")) { - optimizeTranslationByLazyEvaluation = Boolean.parseBoolean(value); } - else { throw new Error("Unknown DBT option: " + key); } Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-08 10:22:45 UTC (rev 162) @@ -143,10 +143,18 @@ super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); - if (DBT_Options.optimizeTranslationByLazyEvaluation) + switch (ARM_Options.flagBehaviour) { + case ImmediateEvaluation: + flagBehavior = new ARM_ImmediateFlagBehavior(); + break; + + case LazyEvaluation: flagBehavior = new ARM_LazyFlagBehavior(); - else - flagBehavior = new ARM_ImmediateFlagBehavior(); + break; + + default: + throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagBehaviour); + } } /** ARM has an interchangeable flag behavior. Flags can either be evaluated immediately or on demand using Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Laziness.java 2007-08-08 10:22:45 UTC (rev 162) @@ -13,7 +13,7 @@ } /** The state of the different ARM flags, compressed as bit fields within an integer. */ - private int flagValid; + private int validFlags; /** The operation that has to be performed to evaluate the remaining registers */ private Operation lazinessOperation; @@ -36,7 +36,7 @@ ARM_LazinessKey(int pc, ARM_Laziness lazy) { this.pc = pc; - int tmpFlagState = lazy.flagValid & 0xF; + int tmpFlagState = lazy.validFlags & 0xF; tmpFlagState |= (lazinessOperation.ordinal() + 1) << 4; this.flagState = (byte)tmpFlagState; @@ -48,7 +48,7 @@ } public ARM_Laziness() { - flagValid = 0xF; //all flags are valid + validFlags = 0xF; //all flags are valid lazinessOperation = Operation.Add; } @@ -57,22 +57,15 @@ } public void setValid(Flag flag, boolean valid) { - flagValid |= 1 << flag.ordinal(); + if (valid) + validFlags |= 1 << flag.ordinal(); + else + validFlags &= ~(1 << flag.ordinal()); } public boolean isValid(Flag flag) { - return (flagValid & (1 << flag.ordinal())) != 0; + return (validFlags & (1 << flag.ordinal())) != 0; } - - public void setAddOperation() { - flagValid = 0; // all flags are invalid - lazinessOperation = Operation.Add; - } - - public void setSubOperation() { - flagValid = 0; // all flags are invalid - lazinessOperation = Operation.Sub; - } public Operation getOperation() { return lazinessOperation; @@ -83,7 +76,7 @@ } public void set(ARM_Laziness other) { - flagValid = other.flagValid; + validFlags = other.validFlags; lazinessOperation = other.lazinessOperation; } @@ -98,7 +91,7 @@ return false; ARM_Laziness other = (ARM_Laziness)o; - return flagValid == other.flagValid && lazinessOperation == other.lazinessOperation; + return validFlags == other.validFlags && lazinessOperation == other.lazinessOperation; } @Override Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-08 10:22:45 UTC (rev 162) @@ -1,5 +1,18 @@ package org.binarytranslator.arch.arm.decoder; public class ARM_Options { + + public enum FlagBehaviour { + LazyEvaluation, + ImmediateEvaluation + } + + /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; + + /** This variable describes, if the translated program shall be optimized using profiling information. */ + public static boolean optimizeTranslationByProfiling = false; + + /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ + public static FlagBehaviour flagBehaviour = FlagBehaviour.LazyEvaluation; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-08 10:22:45 UTC (rev 162) @@ -761,7 +761,7 @@ */ private float getSkipProbability() { - if (DBT_Options.optimizeTranslationByProfiling) + if (ARM_Options.optimizeTranslationByProfiling) return -1f; return ps.branchInfo.getBranchProbability(pc, pc + (inThumb() ? 2 : 4)); @@ -922,7 +922,7 @@ conditionalInstruction.translate(); int followingInstructionAddress = pc + (inThumb() ? 2 : 4); - + //yes it did, so we may need to translate the successor instruction twice if (assumeInstructionWillBeSkipped()) { @@ -935,16 +935,27 @@ lazy.set(lazinessWhenInstructionSkipped); } + condInstructionBlock.setInfrequent(); + nextInstruction_InstructionNotSkipped.setInfrequent(); arm2ir.setNextBlock(nextInstruction_InstructionSkipped); - } else { - //Modify block 4 so that it resolves the different laziness correctly - arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); - nextInstruction_InstructionSkipped.deleteNormalOut(); - arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); - - arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + if (lazy.equivalent(lazinessWhenInstructionSkipped) && conditionalInstruction.getSuccessor(pc) == followingInstructionAddress) { + //the conditional instruction does not change the lazy state, nor does it change the program flow + //therefore, we block 3 and block 4 always execute the same code. We might as well continue with block 4 then. + arm2ir.setNextBlock(nextInstruction_InstructionSkipped); + } + else { + //we can assume that the instruction will rarely be skipped + nextInstruction_InstructionSkipped.setInfrequent(); + + //Modify block 4 so that it resolves the code the be executed if the instruction was skipped + arm2ir.setCurrentBlock(nextInstruction_InstructionSkipped); + nextInstruction_InstructionSkipped.deleteNormalOut(); + arm2ir.appendBranch(followingInstructionAddress, lazinessWhenInstructionSkipped); + + arm2ir.setNextBlock(nextInstruction_InstructionNotSkipped); + } } } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-07 22:28:53 UTC (rev 161) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-08 10:22:45 UTC (rev 162) @@ -754,7 +754,7 @@ DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); return DBT_Options.singleInstrTranslation == false - && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 20) && !shallTraceStop() + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 30) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-11 11:29:13
|
Revision: 163 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=163&view=rev Author: michael_baer Date: 2007-08-11 04:28:50 -0700 (Sat, 11 Aug 2007) Log Message: ----------- - Fixed bugs with Lazy Evaluation - Added option to determine ARM inlining behaviour Modified Paths: -------------- src/org/binarytranslator/DBT.java src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/generic/decoder/CodeTranslator.java Modified: src/org/binarytranslator/DBT.java =================================================================== --- src/org/binarytranslator/DBT.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/DBT.java 2007-08-11 11:28:50 UTC (rev 163) @@ -17,7 +17,7 @@ */ public final class DBT { /** Should the following assertion be checked? */ - public static final boolean VerifyAssertions = true; + public static final boolean VerifyAssertions = VM.VerifyAssertions; /** * Assert the following condition is true, if false then fail with stack trace Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/DBT_Options.java 2007-08-11 11:28:50 UTC (rev 163) @@ -25,7 +25,7 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = true; + public final static boolean profileDuringInterpretation = false; /** Debug binary loading */ public final static boolean debugLoader = true; @@ -182,8 +182,10 @@ private static void parseArmOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { ARM_Options.optimizeTranslationByProfiling = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("flagBehaviour")) { - ARM_Options.flagBehaviour = ARM_Options.FlagBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("flagEvaluation")) { + ARM_Options.flagEvaluation = ARM_Options.FlagBehaviour.valueOf(value); + } else if (key.equalsIgnoreCase("inlining")) { + ARM_Options.inlining = ARM_Options.InliningBehaviour.valueOf(value); } else { throw new Error("Unknown ARM option: " + key); Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/Main.java 2007-08-11 11:28:50 UTC (rev 163) @@ -105,7 +105,7 @@ //on SUN's VM, only the interpreter has been tested if (DBT_Options.buildForSunVM) { - DBT_Options.executionController = ExecutionController.Type.StagedEmulation; + DBT_Options.executionController = ExecutionController.Type.Interpreter; } //load a previously saved branch profile from file, if the user requested it Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-11 11:28:50 UTC (rev 163) @@ -9,6 +9,7 @@ import org.binarytranslator.arch.arm.os.process.ARM_ProcessSpace; import org.binarytranslator.arch.arm.os.process.ARM_Registers; import org.binarytranslator.arch.arm.os.process.ARM_Registers.OperatingMode; +import org.binarytranslator.generic.branchprofile.BranchProfile.BranchType; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Laziness; import org.binarytranslator.vmInterface.DBT_Trace; @@ -143,17 +144,17 @@ super(context, trace); translator = new ARM_Translator((ARM_ProcessSpace)ps, this); - switch (ARM_Options.flagBehaviour) { - case ImmediateEvaluation: + switch (ARM_Options.flagEvaluation) { + case Immediate: flagBehavior = new ARM_ImmediateFlagBehavior(); break; - case LazyEvaluation: + case Lazy: flagBehavior = new ARM_LazyFlagBehavior(); break; default: - throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagBehaviour); + throw new RuntimeException("Unexpected flag behaviour: " + ARM_Options.flagEvaluation); } } @@ -409,7 +410,6 @@ @Override public void onFlagRead(Flag flag, ARM_Laziness lazy) { resolveFlag(flag, lazy); - } @Override @@ -463,6 +463,32 @@ return result; } + @Override + protected boolean inlineBranchInstruction(int targetPc, UnresolvedJumpInstruction jump) { + + switch (ARM_Options.inlining) + { + case Default: + return super.inlineBranchInstruction(targetPc, jump); + + case DynamicJumps: + if (jump.type == BranchType.INDIRECT_BRANCH) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + + case Functions: + if (jump.type == BranchType.CALL || jump.type == BranchType.RETURN) + return true; + else + return super.inlineBranchInstruction(targetPc, jump); + + default: + throw new RuntimeException("Unexpected inlining type."); + } + + } + /** * Returns a RegisterOperand that contains a reference to the currently used ARM_Registers instance. * Use this reference when calling functions on ARM_Registers. @@ -648,18 +674,20 @@ } public void appendLogicalFlags(ARM_Laziness lazy, OPT_Operand result) { + zeroUsed = negativeUsed = true; flagBehavior.appendLogicalFlags(lazy, result); } public void appendSubFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + zeroUsed = negativeUsed = carryUsed = overflowUsed = true; flagBehavior.appendSubFlags(lazy, result, op1, op2); } public void appendAddFlags(ARM_Laziness lazy, OPT_Operand result, OPT_Operand op1, OPT_Operand op2) { + zeroUsed = negativeUsed = carryUsed = overflowUsed = true; flagBehavior.appendAddFlags(lazy, result, op1, op2); } - - + @Override protected OPT_Register[] getUnusedRegisters() { Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Instructions.java 2007-08-11 11:28:50 UTC (rev 163) @@ -1026,7 +1026,7 @@ public LongMultiply(int instr) { super(instr); - unsigned = Utils.getBit(instr, 22); + unsigned = !Utils.getBit(instr, 22); updateConditionCodes = Utils.getBit(instr, 20); accumulate = Utils.getBit(instr, 21); RdHigh = (byte) Utils.getBits(instr, 16, 19); Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-08-11 11:28:50 UTC (rev 163) @@ -1375,8 +1375,8 @@ //get rid of the signs, if we're supposed to do unsigned multiplication if (i.unsigned) { - operand1 &= 0xFFFFFFFF; - operand2 &= 0xFFFFFFFF; + operand1 &= (long)0xFFFFFFFFL; + operand2 &= (long)0xFFFFFFFFL; } // calculate the result @@ -1385,7 +1385,7 @@ if (i.accumulate) { //treat the register as an unsigned value long operand = regs.get(i.getRdLow()); - operand &= 0xFFFFFFFF; + operand &= 0xFFFFFFFFL; result += operand; result += regs.get(i.getRdHigh()) << 32; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-11 11:28:50 UTC (rev 163) @@ -3,10 +3,16 @@ public class ARM_Options { public enum FlagBehaviour { - LazyEvaluation, - ImmediateEvaluation + Lazy, + Immediate } + public enum InliningBehaviour { + Default, + Functions, + DynamicJumps + } + /** Set to true to enable a fastpath for the decoding of data processing instructions.. */ public final static boolean DATAPROCESSING_DECODER_FASTPATH = false; @@ -14,5 +20,7 @@ public static boolean optimizeTranslationByProfiling = false; /** This variable describes, if the translated program shall be optimized using lazy evaluation.*/ - public static FlagBehaviour flagBehaviour = FlagBehaviour.LazyEvaluation; + public static FlagBehaviour flagEvaluation = FlagBehaviour.Lazy; + + public static InliningBehaviour inlining = InliningBehaviour.Default; } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-11 11:28:50 UTC (rev 163) @@ -92,6 +92,9 @@ else instr = ARM_InstructionDecoder.ARM32.decode(instruction, translatorFactory); + if (DBT_Options.debugTranslation) + System.out.println("Translating instruction: " + ARM_Disassembler.disassemble(pc, ps).asString() + " at 0x" + Integer.toHexString(pc)); + if (instr.getCondition() != Condition.AL) { instr = new ConditionalDecorator(instr); } @@ -1327,24 +1330,27 @@ public void translate() { OPT_Operand operand1 = resolveOperand1(); - OPT_Operand operand2 = resolveOperand2(); + OPT_Operand originalOperand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); OPT_BasicBlock addWithoutCarry = arm2ir.createBlockAfterCurrent(); OPT_BasicBlock addWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); + + OPT_RegisterOperand operand2 = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Move.create(INT_MOVE, operand2, originalOperand2)); //Is the carry set at all? if not, just jump to addWithoutCarry - arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2)); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(0), OPT_ConditionOperand.EQUAL(), addWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(addWithCarry); //Yes, the carry flag is set. Pre-increase the result by one to account for the carry. arm2ir.setCurrentBlock(addWithCarry); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, operand2.copyRO(), operand2.copy(), new OPT_IntConstantOperand(1))); addWithCarry.insertOut(addWithoutCarry); //Finally, add the second operands to the result arm2ir.setCurrentBlock(addWithoutCarry); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, operand1, operand2.copy())); setAddResult(result, operand1, operand2); } } @@ -1358,24 +1364,27 @@ public void translate() { OPT_Operand operand1 = resolveOperand1(); - OPT_Operand operand2 = resolveOperand2(); + OPT_Operand originalOperand2 = resolveOperand2(); OPT_RegisterOperand result = getResultRegister(); OPT_BasicBlock subWithoutCarry = arm2ir.createBlockAfterCurrent(); OPT_BasicBlock subWithCarry = arm2ir.createBlockAfterCurrentNotInCFG(); + + OPT_RegisterOperand operand2 = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Move.create(INT_MOVE, operand2, originalOperand2)); //Is the carry set? if yes, just jump to subWithoutCarry - arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2)); arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, arm2ir.getTempValidation(0), arm2ir.readCarryFlag(lazy), new OPT_IntConstantOperand(1), OPT_ConditionOperand.EQUAL(), subWithoutCarry.makeJumpTarget(), new OPT_BranchProfileOperand())); arm2ir.getCurrentBlock().insertOut(subWithCarry); //No, the carry flag is not set. That means, we have to use the carry within the subtraction (weird arm logic). arm2ir.setCurrentBlock(subWithCarry); - arm2ir.appendInstruction(Binary.create(INT_SUB, result.copyRO(), result.copy(), new OPT_IntConstantOperand(1))); + arm2ir.appendInstruction(Binary.create(INT_ADD, operand2.copyRO(), operand2.copy(), new OPT_IntConstantOperand(1))); subWithCarry.insertOut(subWithoutCarry); //Finally, subtract the second operands from the result arm2ir.setCurrentBlock(subWithoutCarry); + arm2ir.appendInstruction(Binary.create(INT_SUB, result, operand1, operand2.copy())); setSubResult(result, operand1, operand2); } } @@ -1846,7 +1855,7 @@ } public int getSuccessor(int pc) { - if (i.offset.getType() == OperandWrapper.Type.Immediate) + if (i.offset.getType() == OperandWrapper.Type.Immediate && !i.link) return readPC() + i.getOffset().getImmediate(); else return -1; @@ -1993,8 +2002,8 @@ if (i.unsigned) { //treat the original ints as unsigned, so get rid of the signs for the longs - arm2ir.appendInstruction(Binary.create(LONG_AND, operand1.copyRO(), operand1.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); - arm2ir.appendInstruction(Binary.create(LONG_AND, operand2.copyRO(), operand2.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand1.copyRO(), operand1.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); + arm2ir.appendInstruction(Binary.create(LONG_AND, operand2.copyRO(), operand2.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); } //multiply the two operands @@ -2005,7 +2014,7 @@ OPT_Operand operand3 = arm2ir.getRegister(i.getRdLow()); OPT_RegisterOperand tmp = arm2ir.getTempLong(0); arm2ir.appendInstruction(Unary.create(INT_2LONG, tmp, operand3)); - arm2ir.appendInstruction(Binary.create(LONG_AND, tmp.copyRO(), tmp.copy(), new OPT_LongConstantOperand(0xFFFFFFFF))); + arm2ir.appendInstruction(Binary.create(LONG_AND, tmp.copyRO(), tmp.copy(), new OPT_LongConstantOperand(0xFFFFFFFFL))); arm2ir.appendInstruction(Binary.create(LONG_ADD, result.copyRO(), result.copy(), tmp.copy())); operand3 = arm2ir.getRegister(i.getRdHigh()); @@ -2013,6 +2022,10 @@ arm2ir.appendInstruction(Binary.create(LONG_SHL, tmp.copyRO(), tmp.copy(), new OPT_IntConstantOperand(32))); arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3.copy())); } + + arm2ir.appendInstruction(Unary.create(LONG_2INT, arm2ir.getRegister(i.getRdLow()) ,result.copy())); + arm2ir.appendInstruction(Binary.create(LONG_SHR, result.copyRO(), result.copy(), new OPT_IntConstantOperand(32))); + arm2ir.appendInstruction(Unary.create(LONG_2INT, arm2ir.getRegister(i.getRdHigh()) ,result.copy())); if (i.updateConditionCodes) { //set the negative flag @@ -2054,10 +2067,10 @@ //do we have to transfer the saved or the current PSR? if (i.transferSavedPSR) { - call = createCallToRegisters("getSPSR", "()V", 0); + call = createCallToRegisters("getSPSR", "()I", 0); } else { - call = createCallToRegisters("getCPSR", "()V", 0); + call = createCallToRegisters("getCPSR", "()I", 0); } Call.setResult(call, psrValue); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-08 10:22:45 UTC (rev 162) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-11 11:28:50 UTC (rev 163) @@ -165,7 +165,7 @@ /** This class stores information about a jump instruction within the current trace, whose * target has not yet been resolved. */ - private final static class UnresolvedJumpInstruction { + protected final static class UnresolvedJumpInstruction { /** A reference to the jump instruction within the code. This is either a GOTO or SWITCH instruction. */ public final OPT_Instruction instruction; @@ -306,6 +306,10 @@ // Move currentBlock along currentBlock = nextBlock; } else { + + if (DBT_Options.debugTranslation) + System.out.println("Translating subtrace for 0x" + Integer.toHexString(pc)); + do { if (DBT.VerifyAssertions) DBT._assert(currentBlock.getNumberOfRealInstructions() == 0); @@ -351,6 +355,9 @@ break; } } while (pc != -1); + + if (DBT_Options.debugTranslation) + System.out.println("Done translating subtrace."); } } @@ -608,7 +615,7 @@ // serves more as a placeholder and might be mutated later on. appendInstruction(branch); UnresolvedJumpInstruction unresolvedJump = new UnresolvedJumpInstruction( - branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, BranchType.CALL); + branch, (Laziness) targetLaziness.clone(), currentPC, targetPC, branchType); unresolvedDirectBranches.add(unresolvedJump); switch (branchType) { @@ -753,9 +760,17 @@ DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); - return DBT_Options.singleInstrTranslation == false - && (compiledTrace == null || compiledTrace.getNumberOfInstructions() > 30) && !shallTraceStop() + boolean decision = DBT_Options.singleInstrTranslation == false + && (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) && !shallTraceStop() && jump.type != BranchType.CALL && jump.type != BranchType.RETURN; + + if (DBT_Options.debugBranchResolution) { + String text = (!decision ? "Not inlining " : "Inlining "); + text += jump.type + " to 0x" + Integer.toHexString(targetPc); + System.out.println(text); + } + + return decision; } /** @@ -782,21 +797,19 @@ // precompiled target if (targetBB != null) return targetBB; - + + if (currentBlock.getNumberOfRealInstructions() != 0) { + currentBlock = createBlockAfterCurrentNotInCFG(); + } + if (!inlineBranchInstruction(targetPc, jump)) { - // Just exit the trace and continue at the target address in a new trace - if (currentBlock.getNumberOfRealInstructions() != 0) { - currentBlock = createBlockAfterCurrentNotInCFG(); - - if (DBT_Options.debugBranchResolution) - System.out.println("Resolving branch to next block."); - } - + //Just exit the trace and continue at the target address in a new trace targetBB = currentBlock; appendTraceExit(jump.lazyStateAtJump, new OPT_IntConstantOperand(targetPc)); registerMapping(targetPc, jump.lazyStateAtJump, targetBB); - } else { + } + else { // Otherwise we will translate the jump into the trace translateSubTrace((Laziness) jump.lazyStateAtJump.clone(), targetPc); targetBB = findMapping(targetPc, jump.lazyStateAtJump); @@ -1299,7 +1312,9 @@ */ public void appendInterpretedInstruction(int pc, Laziness lazy) { - resolveLaziness(lazy); + appendThrowBadInstruction(lazy, pc); + +/* resolveLaziness(lazy); spillAllRegisters(); // Prepare a local variable of type Interpreter @@ -1313,7 +1328,7 @@ VM_MethodReference getInterpreterMethodRef = (VM_MethodReference) VM_MemberReference .findOrCreate(psTref, VM_Atom .findOrCreateAsciiAtom("createInstructionInterpreter"), VM_Atom - .findOrCreateAsciiAtom("()A")); + .findOrCreateAsciiAtom("()Lorg.binarytranslator.generic.decoder.Interpreter;")); VM_Method getInterpreterMethod = getInterpreterMethodRef .resolveInterfaceMethod(); @@ -1345,7 +1360,7 @@ VM_MethodReference decodeMethodRef = (VM_MethodReference) VM_MemberReference .findOrCreate(interpreterTypeRef, VM_Atom .findOrCreateAsciiAtom("decode"), VM_Atom - .findOrCreateAsciiAtom("(I)A")); + .findOrCreateAsciiAtom("(I)Lorg.binarytranslator.generic.decoder.Interpreter.Instruction;")); VM_Method decodeMethod = decodeMethodRef.resolveInterfaceMethod(); methOp = OPT_MethodOperand.INTERFACE(decodeMethodRef, decodeMethod); @@ -1385,7 +1400,7 @@ appendCustomCall(s); // Fill all registers again following interpreted instruction - fillAllRegisters(); + fillAllRegisters();*/ } /** Get the method */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-14 17:25:21
|
Revision: 165 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=165&view=rev Author: michael_baer Date: 2007-08-14 10:25:25 -0700 (Tue, 14 Aug 2007) Log Message: ----------- - Fixed bug with overlapping translator registers during MultiplyAccumulate - Check in missing file from last commit Modified Paths: -------------- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java Added Paths: ----------- src/org/binarytranslator/generic/fault/InsufficientMemoryException.java Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-14 15:32:09 UTC (rev 164) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-14 17:25:25 UTC (rev 165) @@ -1955,12 +1955,16 @@ OPT_RegisterOperand result = arm2ir.getRegister(i.Rd); //calculate the result - arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); - if (i.accumulate) { + OPT_RegisterOperand tmp = arm2ir.getTempInt(0); + arm2ir.appendInstruction(Binary.create(INT_MUL, tmp, operand1, operand2)); + OPT_Operand operand3 = arm2ir.getRegister(i.Rn); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), result.copy(), operand3)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), tmp.copy(), operand3)); } + else { + arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); + } if (i.updateConditionCodes) { //set the negative & zero flag Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 15:32:09 UTC (rev 164) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) @@ -665,7 +665,7 @@ } writeString(cmdLine, ptrBuffer); - ps.memory.store32(ptrParamBlock + 4, cmdLine.length() + 1); + ps.memory.store32(ptrParamBlock + 4, cmdLine.length()); setReturn(0); } } Added: src/org/binarytranslator/generic/fault/InsufficientMemoryException.java =================================================================== --- src/org/binarytranslator/generic/fault/InsufficientMemoryException.java (rev 0) +++ src/org/binarytranslator/generic/fault/InsufficientMemoryException.java 2007-08-14 17:25:25 UTC (rev 165) @@ -0,0 +1,20 @@ +package org.binarytranslator.generic.fault; + +import org.binarytranslator.generic.os.process.ProcessSpace; + +/** + * Thrown when a process space runs out of (virtual) memory when performing an operation. + * + */ +public class InsufficientMemoryException extends RuntimeException { + private final String operation; + + public InsufficientMemoryException(ProcessSpace ps, String operation) { + this.operation = operation; + } + + @Override + public String toString() { + return "InsufficientMemoryException (Operation: " + operation + ")"; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-15 11:08:39
|
Revision: 166 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=166&view=rev Author: michael_baer Date: 2007-08-15 04:08:41 -0700 (Wed, 15 Aug 2007) Log Message: ----------- - Disabled debug output by default - added options to show arm stack and heap range Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/DBT_Options.java 2007-08-15 11:08:41 UTC (rev 166) @@ -25,11 +25,8 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = false; + public final static boolean profileDuringInterpretation = true; - /** Debug binary loading */ - public final static boolean debugLoader = true; - /** Are unimplemented system calls fatal? */ public final static boolean unimplementedSystemCallsFatal = false; @@ -77,38 +74,41 @@ public final static boolean eliminateRegisterFills = true; /** Print dissassembly of translated instructions. */ - public static boolean debugInstr = true; + public static boolean debugInstr = false; /** Print information about the lazy resolution of branch addresses...*/ - public static boolean debugBranchResolution = true; + public static boolean debugBranchResolution = false; /** During code translation, print information about the creation of basic blocks. */ public final static boolean debugCFG = false; - - /** Debug using GDB? */ - public static boolean gdbStub = false; - - /** GDB stub port */ - public static int gdbStubPort = 1234; - /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ - public static int minTraceValue = 20; + /** Debug binary loading */ + public static boolean debugLoader = false; /** Print debug information during the translation of instructions. */ - public static boolean debugTranslation = true; + public static boolean debugTranslation = false; /** In ProcessSpace, print syscall numbers. */ - public static boolean debugSyscall = true; + public static boolean debugSyscalls = false; /** In ProcessSpace, print syscall numbers. */ - public static boolean debugSyscallMore = false; + public static boolean debugSyscallsMore = false; /** Print out various messages about the emulator starting. */ - public static boolean debugRuntime = true; + public static boolean debugRuntime = false; /** Print out messages from the memory system */ public static boolean debugMemory = false; + + /** Debug using GDB? */ + public static boolean gdbStub = false; + + /** GDB stub port */ + public static int gdbStubPort = 1234; + /** Just a temporary variable for testing. It describes, when the staged emulation controller switches from interpretation to translation. */ + public static int minTraceValue = 20; + /** Inline calls to descendents of callbased memory? */ public static boolean inlineCallbasedMemory = false; @@ -204,12 +204,14 @@ debugBranchResolution = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugMemory")) { debugMemory = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("debugSyscall")) { - debugSyscall = Boolean.parseBoolean(value); - } else if (key.equalsIgnoreCase("debugSyscallMore")) { - debugSyscallMore = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugSyscalls")) { + debugSyscalls = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugSyscallsMore")) { + debugSyscallsMore = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("debugTranslation")) { debugTranslation = Boolean.parseBoolean(value); + } else if (key.equalsIgnoreCase("debugLoader")) { + debugLoader = Boolean.parseBoolean(value); } else if (key.equalsIgnoreCase("instrOpt0")) { instrOpt0 = Integer.parseInt(value); } else if (key.equalsIgnoreCase("instrOpt1")) { Modified: src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/arch/arm/os/abi/semihosting/AngelSystemCalls.java 2007-08-15 11:08:41 UTC (rev 166) @@ -107,7 +107,7 @@ public void doSysCall(int callNum) { try { - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.out.println("Executing Angel Syscall: " + callNum); sysCalls[callNum].execute(); @@ -310,7 +310,7 @@ String fileName = readString(ptrBuffer, length); - if (DBT_Options.debugSyscallMore) + if (DBT_Options.debugSyscallsMore) System.out.println("Opening file: " + fileName); try { Modified: src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java =================================================================== --- src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-08-14 17:25:25 UTC (rev 165) +++ src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-08-15 11:08:41 UTC (rev 166) @@ -187,7 +187,7 @@ public void doSysCall() { int sysCallNumber = src.getSysCallNumber(); - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.err.println("Syscall " + sysCallToString(sysCallNumber)); arguments = src.getSysCallArguments(); @@ -357,7 +357,7 @@ // accordingly. args[0] points to the file name. String fileName = memoryReadString(pathname); - if (DBT_Options.debugSyscall) + if (DBT_Options.debugSyscalls) System.err.println("Program tries to open: " + fileName); FileMode mode; @@ -527,7 +527,7 @@ String filename = memoryReadString(ptrFilename); - if (DBT_Options.debugSyscallMore) + if (DBT_Options.debugSyscallsMore) System.err.println("Stat64() denies existance of file: " + filename); src.setSysCallError(errno.ENOENT); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-20 14:13:04
|
Revision: 168 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=168&view=rev Author: michael_baer Date: 2007-08-20 07:12:59 -0700 (Mon, 20 Aug 2007) Log Message: ----------- - Fixed bug in IntAddressed Memory for 16bit unsigned loads - Renamed IntAddressedMemory to IntAddressedLittleEndian Memory - Renamed ByteAddressedMemory to ByteAddressedLittleEndian Memory Modified Paths: -------------- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java src/org/binarytranslator/generic/memory/IntAddressedPreSwappedMemory.java Added Paths: ----------- src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java Removed Paths: ------------- src/org/binarytranslator/generic/memory/ByteAddressedMemory.java src/org/binarytranslator/generic/memory/IntAddressedMemory.java Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -10,8 +10,8 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; -import org.binarytranslator.generic.memory.ByteAddressedMemory; -import org.binarytranslator.generic.memory.IntAddressedMemory; +import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; +import org.binarytranslator.generic.memory.IntAddressedLittleEndianMemory; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; @@ -43,11 +43,11 @@ switch (ARM_Options.memoryModel) { case ByteAddressed: - memory = new ByteAddressedMemory(); + memory = new ByteAddressedLittleEndianMemory(); break; case IntAddressed: - memory = new IntAddressedMemory(); + memory = new IntAddressedLittleEndianMemory(); break; default: Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -14,8 +14,8 @@ public class ARM_ImageProcessSpace extends ARM_ProcessSpace { private AngelSystemCalls sysCalls; - private final int STACK_SIZE = 4096 * 10; - private final int HEAP_SIZE = 4096 * 10; + private final int STACK_SIZE = 4096 * 100; + private final int HEAP_SIZE = 4096 * 100; public ARM_ImageProcessSpace() { super(); Modified: src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/arch/x86/os/process/X86_ProcessSpace.java 2007-08-20 14:12:59 UTC (rev 168) @@ -14,7 +14,7 @@ import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.process.ProcessSpace; -import org.binarytranslator.generic.memory.ByteAddressedMemory; +import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.BadInstructionException; @@ -139,7 +139,7 @@ */ protected X86_ProcessSpace() { registers = new X86_Registers(); - memory = new ByteAddressedMemory(); + memory = new ByteAddressedLittleEndianMemory(); } /** Modified: src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/ByteAddressedByteSwapMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -29,7 +29,7 @@ * .........00 |'H'| * </pre> */ -final public class ByteAddressedByteSwapMemory extends ByteAddressedMemory { +final public class ByteAddressedByteSwapMemory extends ByteAddressedLittleEndianMemory { /** * Constructor - used when this is the instatiated class */ Copied: src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java (from rev 149, src/org/binarytranslator/generic/memory/ByteAddressedMemory.java) =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/ByteAddressedLittleEndianMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -0,0 +1,550 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; + +/** + * ByteAddressedMemory: + * + * Memory is arrays of bytes, no endian conversion is performed. + * + * The string helo followed by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address| + * ----------------- + * .........07 | ca| + * .........06 | fe| + * .........05 | ba| + * .........04 | be| + * .........03 |'o'| + * .........02 |'l'| + * .........01 |'e'| + * .........00 |'H'| + * </pre> + */ +public class ByteAddressedLittleEndianMemory extends CallBasedMemory { + + /** The size of a single page in bytes. */ + private static final int PAGE_SIZE = 4096; + + /** Bits in offset */ + private static final int OFFSET_BITS = 12; + + /** The number of pages */ + private static final int NUM_PAGES = 0x100000; + + /** The maximum amount of RAM available */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** The memory backing store */ + private byte readableMemory[][]; + private byte writableMemory[][]; + private byte executableMemory[][]; + + /** Do we have more optimal nio mmap operation? */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public ByteAddressedLittleEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the name of the over-riding class + */ + protected ByteAddressedLittleEndianMemory(Class classType) { + super(classType != null ? classType : ByteAddressedLittleEndianMemory.class); + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + + if (DBT_Options.debugMemory) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate pages + readableMemory[pte + i] = read ? pages[i] : null; + writableMemory[pte + i] = write ? pages[i] : null; + executableMemory[pte + i] = exec ? pages[i] : null; + } + + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + + readableMemory[pte + i] = read ? page : null; + writableMemory[pte + i] = write ? page : null; + executableMemory[pte + i] = exec ? page : null; + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate page + if (read && write) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + writableMemory[pte + i] = readableMemory[pte + i]; + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (read) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (exec) { + executableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + } else { + throw new Error("Unable to map address 0x" + + Integer.toHexString(addr) + " with permissions " + + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + } + } + return addr; + } catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private byte[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + final public int loadSigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)]; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + final public int loadUnsigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + return (loadSigned8(addr + 1) << 8) | loadUnsigned8(addr); + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + return (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + try { + return (loadSigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) + | (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + if (DBT_Options.debugMemory) + System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) + + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); + return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + return (loadInstruction8(addr + 3) << 24) + | (loadInstruction8(addr + 2) << 16) + | (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public final void store8(int addr, int value) { + if (DBT_Options.debugMemory) + System.err.println("Store8 address: 0x" + Integer.toHexString(addr) + + " val: 0x" + Integer.toHexString(value & 0xFF)); + writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + store8(addr + 1, value >> 8); + store8(addr, value); + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + try { + store8(addr + 3, value >> 24); + store8(addr + 2, value >> 16); + store8(addr + 1, value >> 8); + store8(addr, value); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + byte[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + @Override + public int loadInstruction16(int addr) { + return (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); + } +} Deleted: src/org/binarytranslator/generic/memory/ByteAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/ByteAddressedMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -1,550 +0,0 @@ -/* - * This file is part of binarytranslator.org. The binarytranslator.org - * project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 - */ -package org.binarytranslator.generic.memory; - -import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; -import org.binarytranslator.DBT_Options; -import org.binarytranslator.generic.fault.SegmentationFault; - -/** - * ByteAddressedMemory: - * - * Memory is arrays of bytes, no endian conversion is performed. - * - * The string helo followed by the int of 0xcafebabe appear as: - * - * <pre> - * Byte Address| - * ----------------- - * .........07 | be| - * .........06 | ba| - * .........05 | fe| - * .........04 | ca| - * .........03 |'o'| - * .........02 |'l'| - * .........01 |'e'| - * .........00 |'H'| - * </pre> - */ -public class ByteAddressedMemory extends CallBasedMemory { - - /** The size of a single page in bytes. */ - private static final int PAGE_SIZE = 4096; - - /** Bits in offset */ - private static final int OFFSET_BITS = 12; - - /** The number of pages */ - private static final int NUM_PAGES = 0x100000; - - /** The maximum amount of RAM available */ - protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; - - /** The memory backing store */ - private byte readableMemory[][]; - private byte writableMemory[][]; - private byte executableMemory[][]; - - /** Do we have more optimal nio mmap operation? */ - private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; - - /** - * Constructor - used when this is the instatiated class - */ - public ByteAddressedMemory() { - this(null); - } - - /** - * Constructor - used when deriving a class - * - * @param classType - * the name of the over-riding class - */ - protected ByteAddressedMemory(Class classType) { - super(classType != null ? classType : ByteAddressedMemory.class); - readableMemory = new byte[NUM_PAGES][]; - writableMemory = new byte[NUM_PAGES][]; - executableMemory = new byte[NUM_PAGES][]; - } - - /** - * Return the offset part of the address - */ - private static final int getOffset(int address) { - return address & (PAGE_SIZE - 1); - } - - /** - * Return the page table entry part of the address - */ - private static final int getPTE(int address) { - return address >>> OFFSET_BITS; - } - - /** - * Find free consecutive pages - * - * @param pages - * the number of pages required - * @return the address found - */ - private final int findFreePages(int pages) { - starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { - if (getPage(i) == null) { - int start = i; - int end = i + pages; - for (; i <= end; i++) { - if (getPage(i) != null) { - continue starting_page_search; - } - } - return start << OFFSET_BITS; - } - } - throw new Error( - "No mappable consecutive pages found for an anonymous map of size" - + (pages * PAGE_SIZE)); - } - - /** - * Map an anonymous page of memory - * - * @param addr - * the address to map or NULL if don't care - * @param len - * the amount of memory to map - * @param read - * is the page readable - * @param write - * is the page writable - * @param exec - * is the page executable - */ - public int map(int addr, int len, boolean read, boolean write, boolean exec) - throws MemoryMapException { - // Check address is page aligned - if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); - } - - // Create memory - int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; - byte pages[][] = new byte[num_pages][PAGE_SIZE]; - - // Find address if not specified - if (addr == 0) { - addr = findFreePages(num_pages); - } - - if (DBT_Options.debugMemory) { - System.out.println("Anonymous mapping: addr=0x" - + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") - + (write ? "w" : "-") + (exec ? "x" : "-")); - } - - // Get page table entry - int pte = getPTE(addr); - for (int i = 0; i < num_pages; i++) { - - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - - // Allocate pages - readableMemory[pte + i] = read ? pages[i] : null; - writableMemory[pte + i] = write ? pages[i] : null; - executableMemory[pte + i] = exec ? pages[i] : null; - } - - return addr; - } - - /** - * Map a page of memory from file - * - * @param file - * the file map in from - * @param addr - * the address to map or NULL if don't care - * @param len - * the amount of memory to map - * @param read - * is the page readable - * @param write - * is the page writable - * @param exec - * is the page executable - */ - public int map(RandomAccessFile file, long offset, int addr, int len, - boolean read, boolean write, boolean exec) throws MemoryMapException { - // Check address is page aligned - if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); - } - - // Check file offset is page aligned - /*if ((offset % PAGE_SIZE) != 0) { - MemoryMapException.unalignedFileOffset(offset); - }*/ - - // Calculate number of pages - int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; - // Find address if not specified - if (addr == 0) { - addr = findFreePages(num_pages); - } - if (DBT_Options.debugMemory) { - System.out.println("Mapping file " + file + " offset=" + offset - + " addr=0x" + Integer.toHexString(addr) + " len=" + len - + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); - } - try { - // Get page table entry - int pte = getPTE(addr); - // Can we optimise the reads to use mmap? - if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { - // Sub-optimal - file.seek(offset); - for (int i = 0; i < num_pages; i++) { - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - // Allocate page - byte page[] = new byte[PAGE_SIZE]; - if (i == 0) { // first read, start from offset upto a page length - file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); - } else if (i == (num_pages - 1)) { // last read - file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); - } else { - file.read(page); - } - - readableMemory[pte + i] = read ? page : null; - writableMemory[pte + i] = write ? page : null; - executableMemory[pte + i] = exec ? page : null; - } - } else { - for (int i = 0; i < num_pages; i++) { - // Check pages aren't already allocated - if (getPage(pte + i) != null) { - throw new Error("Memory map of already mapped location addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - - // Allocate page - if (read && write) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - writableMemory[pte + i] = readableMemory[pte + i]; - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (read) { - readableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - if (exec) { - executableMemory[pte + i] = readableMemory[pte + i]; - } - } else if (exec) { - executableMemory[pte + i] = file.getChannel().map( - FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), - PAGE_SIZE).array(); - } else { - throw new Error("Unable to map address 0x" - + Integer.toHexString(addr) + " with permissions " - + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); - } - } - } - return addr; - } catch (java.io.IOException e) { - throw new Error(e); - } - } - - /** - * Returns the page currently mapped at the given page table entry. - * - * @param pte - * The page table entry, for which a page is to be retrieved. - * @return - * The page mapped at the given page table entry or null, if no page is currently mapped - * to that entry. - */ - private byte[] getPage(int pte) { - - if (readableMemory[pte] != null) - return readableMemory[pte]; - - if (writableMemory[pte] != null) - return writableMemory[pte]; - - if (executableMemory[pte] != null) - return executableMemory[pte]; - - return null; - } - - /** - * Unmap a page of memory - * - * @param addr - * the address to unmap - * @param len - * the amount of memory to unmap - */ - public void unmap(int addr, int len) { - for (int i = 0; i < len; i += PAGE_SIZE) { - - int pte = getPTE(addr + i); - if (getPage(pte) != null) { - readableMemory[pte] = null; - writableMemory[pte] = null; - executableMemory[pte] = null; - } - else { - throw new Error("Unmapping memory that's not mapped addr=0x" - + Integer.toHexString(addr) + " len=" + len); - } - } - } - - /** - * Is the given address mapped into memory? - * @param addr to check - * @return true => memory is mapped - */ - public boolean isMapped(int addr) { - return getPage(getPTE(addr)) != null; - } - - /** - * @return the size of a page - */ - public int getPageSize() { - return PAGE_SIZE; - } - - /** - * Is the given address aligned on a page boundary? - * - * @param addr - * the address to check - * @return whether the address is aligned - */ - public boolean isPageAligned(int addr) { - return (addr % PAGE_SIZE) == 0; - } - - /** - * Make the given address page aligned to the page beneath it - * - * @param addr - * the address to truncate - * @return the truncated address - */ - public int truncateToPage(int addr) { - return (addr >> OFFSET_BITS) << OFFSET_BITS; - } - - /** - * Make the given address page aligned to the page above it - * - * @param addr - * the address to truncate - * @return the truncated address - */ - public int truncateToNextPage(int addr) { - return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; - } - - /** - * Perform a byte load where the sign extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the sign extended result - */ - final public int loadSigned8(int addr) { - try { - if (DBT_Options.debugMemory) - System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) - + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); - return readableMemory[getPTE(addr)][getOffset(addr)]; - } catch (NullPointerException e) { - System.err.println("Null pointer exception at address: 0x" - + Integer.toHexString(addr)); - throw e; - } - } - - /** - * Perform a byte load where the zero extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the zero extended result - */ - final public int loadUnsigned8(int addr) { - try { - if (DBT_Options.debugMemory) - System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) - + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); - return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; - } catch (NullPointerException e) { - System.err.println("Null pointer exception at address: 0x" - + Integer.toHexString(addr)); - throw e; - } - } - - /** - * Perform a 16bit load where the sign extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the sign extended result - */ - public int loadSigned16(int addr) { - return (loadSigned8(addr + 1) << 8) | loadUnsigned8(addr); - } - - /** - * Perform a 16bit load where the zero extended result fills the return value - * - * @param addr - * the address of the value to load - * @return the zero extended result - */ - public int loadUnsigned16(int addr) { - return (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); - } - - /** - * Perform a 32bit load - * - * @param addr - * the address of the value to load - * @return the result - */ - public int load32(int addr) { - try { - return (loadSigned8(addr + 3) << 24) | (loadUnsigned8(addr + 2) << 16) - | (loadUnsigned8(addr + 1) << 8) | loadUnsigned8(addr); - } catch (Exception e) { - throw new SegmentationFault(addr); - } - } - - /** - * Perform a 8bit load from memory that must be executable - * - * @param addr - * the address of the value to load - * @return the result - */ - public int loadInstruction8(int addr) { - if (DBT_Options.debugMemory) - System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) - + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); - return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; - } - - /** - * Perform a 32bit load from memory that must be executable - * - * @param addr - * the address of the value to load - * @return the result - */ - public int loadInstruction32(int addr) { - return (loadInstruction8(addr + 3) << 24) - | (loadInstruction8(addr + 2) << 16) - | (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); - } - - /** - * Perform a byte store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public final void store8(int addr, int value) { - if (DBT_Options.debugMemory) - System.err.println("Store8 address: 0x" + Integer.toHexString(addr) - + " val: 0x" + Integer.toHexString(value & 0xFF)); - writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; - } - - /** - * Perform a 16bit store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public void store16(int addr, int value) { - store8(addr + 1, value >> 8); - store8(addr, value); - } - - /** - * Perform a 32bit store - * - * @param value - * the value to store - * @param addr - * the address of where to store - */ - public void store32(int addr, int value) { - try { - store8(addr + 3, value >> 24); - store8(addr + 2, value >> 16); - store8(addr + 1, value >> 8); - store8(addr, value); - } catch (Exception e) { - throw new SegmentationFault(addr); - } - } - - @Override - public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { - - while (len > 0) { - int pte = getPTE(address); - byte[] page = getPage(pte); - - if (page == null) - throw new SegmentationFault(address); - - readableMemory[pte] = newRead ? page : null; - writableMemory[pte] = newWrite ? page : null; - executableMemory[pte] = newExec ? page : null; - - address += PAGE_SIZE; - len -= PAGE_SIZE; - } - } - - @Override - public int loadInstruction16(int addr) { - return (loadInstruction8(addr + 1) << 8) | loadInstruction8(addr); - } -} Modified: src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/IntAddressedByteSwapMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -26,7 +26,7 @@ * .........00 |'H'|'e'|'l'|'l'| * </pre> */ -final public class IntAddressedByteSwapMemory extends IntAddressedMemory { +final public class IntAddressedByteSwapMemory extends IntAddressedLittleEndianMemory { /** * Constructor - used when this is the instatiated class */ Copied: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java (from rev 164, src/org/binarytranslator/generic/memory/IntAddressedMemory.java) =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -0,0 +1,673 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; +import org.jikesrvm.VM_Configuration; +import org.vmmagic.pragma.Inline; + +/** + * IntAddressedMemory: + * + * Memory is arrays of ints, no endian conversion is performed. + * + * The string helloworld following by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address + * Int Address | 0 | 1 | 2 | 3 | + * ----------------------------- + * .........0c | be| ba| fe| ca| + * .........08 |'l'|'d'| \n| \0| + * .........04 |'o'|'W'|'o'|'r'| + * .........00 |'H'|'e'|'l'|'l'| + * </pre> + */ +public class IntAddressedLittleEndianMemory extends CallBasedMemory { + /** + * The size of pages + */ + protected static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + protected static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + protected static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private int readableMemory[][]; + + private int writableMemory[][]; + + private int executableMemory[][]; + + /** + * Constructor - used when this is the instatiated class + */ + public IntAddressedLittleEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the type of the over-riding class + */ + protected IntAddressedLittleEndianMemory(Class classType) { + super(classType != null ? classType : IntAddressedLittleEndianMemory.class); + readableMemory = new int[NUM_PAGES][]; + writableMemory = new int[NUM_PAGES][]; + executableMemory = new int[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + @Inline + protected int getOffset(int address) { + return (address & (PAGE_SIZE - 1)) >>> 2; + } + + /** + * Return the page table entry part of the address + */ + @Inline + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check that the address is page aligned + if ((addr % PAGE_SIZE) != 0) { + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); + } + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Create memory + int pages[][] = new int[num_pages][PAGE_SIZE / 4]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugRuntime) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + readableMemory[pte+i] = read ? pages[i] : null; + writableMemory[pte+i] = write ? pages[i] : null; + executableMemory[pte+i] = exec ? pages[i] : null; + } + return addr; + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private int[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + int[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + /** + * Read an int from RandomAccessFile ensuring that a byte swap isn't performed + * + * @param file + * file to read from + * @return native endian read int + */ + protected int readInt(RandomAccessFile file) throws java.io.IOException { + if (VM_Configuration.BuildForPowerPC) { + return file.readInt(); // NB this will always read in big-endian format + } else { + return file.readUnsignedByte() | (file.readUnsignedByte() << 8) + | (file.readUnsignedByte() << 16) | (file.readByte() << 24); + } + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public final int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + if (DBT_Options.debugRuntime) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + addr = map(addr, len, read, write, exec); + + try { + file.seek(offset); + for (int i = 0; i < len; i += 4) { + + int[] page = getPage(getPTE(addr + i)); + page[getOffset(addr + i)] = readInt(file); + } + + return addr; + + } + catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public final void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Perform a 32bit load where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAligned32(int addr) { + return readableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a 32bit load where addr is word aligned and executable + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAlignedInstruction32(int addr) { + return executableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned8(int addr) { + return (loadWordAligned32(addr) << ((3 - (addr & 0x3)) << 3)) >> 24; + // switch(addr & 3) { + // default: + // return (loadWordAligned32(addr) << 24) >> 24; + // case 1: + // return (loadWordAligned32(addr) << 16) >> 24; + // case 2: + // return (loadWordAligned32(addr) << 8) >> 24; + // case 3: + // return loadWordAligned32(addr) >> 24; + // } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned8(int addr) { + return (loadWordAligned32(addr) >> ((addr & 3) << 3)) & 0xFF; + // switch(addr & 3) { + // default: + // return loadWordAligned32(addr) & 0xFF; + // case 1: + // return (loadWordAligned32(addr) >> 8) & 0xFF; + // case 2: + // return (loadWordAligned32(addr) >> 16) & 0xFF; + // case 3: + // return loadWordAligned32(addr) >>> 24; + // } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + switch (addr & 3) { + default: + return (loadWordAligned32(addr) << 16) >> 16; + case 1: + return (loadWordAligned32(addr) << 8) >> 16; + case 2: + return loadWordAligned32(addr) >> 16; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr) >>> 24) + | ((loadWordAligned32(addr + 1) << 24) >> 16); + } + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) & 0xFFFF; + case 1: + return (loadWordAligned32(addr) >> 8) & 0xFFFF; + case 2: + return (loadWordAligned32(addr) >> 16) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr) >>> 24) + | ((loadWordAligned32(addr + 1) << 8) & 0xFF00); + } + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr); + case 1: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 3) & 0xFF) << 24) + | (loadWordAligned32(addr) >>> 8); + case 2: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 2) & 0xFFFF) << 16) + | (loadWordAligned32(addr) >>> 16); + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr + 1) & 0xFFFFFF) << 8) + | (loadWordAligned32(addr) >>> 24); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) & 0xFF; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFF; + case 2: + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFF; + case 3: + return loadWordAlignedInstruction32(addr) >>> 24; + } + } + + @Override + public int loadInstruction16(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 16; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAlignedInstruction32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr) >>> 24) + | ((loadWordAlignedInstruction32(addr + 1) << 8) & 0xFF00); + } + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr); + case 1: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 3) & 0xFF) << 24) + | (loadWordAlignedInstruction32(addr) >>> 8); + case 2: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 2) & 0xFFFF) << 16) + | (loadWordAlignedInstruction32(addr) >>> 16); + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr + 1) & 0xFFFFFF) << 8) + | (loadWordAlignedInstruction32(addr) >>> 24); + } + } + + /** + * Perform a 32bit aligned store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + final protected void storeWordAligned32(int addr, int value) { + writableMemory[getPTE(addr)][getOffset(addr)] = value; + } + + /** + * Perform a 32bit load, from writable memory, where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + final protected int loadWordAligned32forWrite(int addr) { + return writableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store8(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value & 0xFF)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF00FF) + | ((value & 0xFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF00FFFF) + | ((value & 0xFF) << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + break; + } + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value & 0xFFFF)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF0000FF) + | ((value & 0xFFFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0xFFFFFF00) + | ((value >> 8) & 0xFF)); + break; + } + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, value); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x000000FF) + | (value << 8)); + storeWordAligned32(addr + 3, + (loadWordAligned32forWrite(addr + 3) & 0xFFFFFF00) | (value >>> 24)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + storeWordAligned32(addr + 2, + (loadWordAligned32forWrite(addr + 2) & 0xFFFF0000) | (value >>> 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0xFF000000) | (value >>> 8)); + break; + } + } +} Deleted: src/org/binarytranslator/generic/memory/IntAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-15 16:24:05 UTC (rev 167) +++ src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-08-20 14:12:59 UTC (rev 168) @@ -1,673 +0,0 @@ -/* - * This file is part of binarytranslator.org. The binarytranslator.org - * project is distributed under the Common Public License (CPL). - * A copy of the license is included in the distribution, and is also - * available at http://www.opensource.org/licenses/cpl1.0.php - * - * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 - */ -package org.bi... [truncated message content] |
From: <mic...@us...> - 2007-08-21 15:35:45
|
Revision: 170 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=170&view=rev Author: michael_baer Date: 2007-08-21 08:29:38 -0700 (Tue, 21 Aug 2007) Log Message: ----------- - Increase ARM heap & stack size to 4MB when loading embedded system images - Move some OPT_Operand.copy() calls around Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/arch/arm/decoder/ARM2IR.java src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/execution/InterpreterController.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/DBT_Options.java 2007-08-21 15:29:38 UTC (rev 170) @@ -25,7 +25,7 @@ public final static boolean buildForSunVM = false; /** Enable the profiling of application during interpretation? */ - public final static boolean profileDuringInterpretation = true; + public final static boolean profileDuringInterpretation = false; /** Are unimplemented system calls fatal? */ public final static boolean unimplementedSystemCallsFatal = false; Modified: src/org/binarytranslator/arch/arm/decoder/ARM2IR.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/decoder/ARM2IR.java 2007-08-21 15:29:38 UTC (rev 170) @@ -413,7 +413,7 @@ appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.BORROW_FROM_SUB().flipCode(), new OPT_BranchProfileOperand())); } else { - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Carry), op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.LOWER().flipCode(), new OPT_BranchProfileOperand())); } break; @@ -431,7 +431,7 @@ case Add: case LogicalOpAfterAdd: if (ARM_Options.useOptimizedFlags) { - appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, getFlag(Flag.Overflow), op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); + appendInstruction(BooleanCmp.create(BOOLEAN_CMP_INT, flagRegister, op1.copy(), op2.copy(), OPT_ConditionOperand.OVERFLOW_FROM_ADD(), OPT_BranchProfileOperand.unlikely())); } else { OPT_RegisterOperand tmp1 = getTempInt(5); @@ -442,7 +442,7 @@ appendInstruction(Binary.create(INT_SUB, tmp2.copyRO(), new OPT_IntConstantOperand(Integer.MIN_VALUE), op2.copy())); appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, tmp_bool.copyRO(), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.GREATER_EQUAL(), new OPT_BranchProfileOperand(), op1.copy(), tmp1.copy(), OPT_ConditionOperand.GREATER(), OPT_BranchProfileOperand.unlikely())); appendInstruction(BooleanCmp2.create(BOOLEAN_CMP2_INT_AND, getFlag(Flag.Overflow), op2.copy(), new OPT_IntConstantOperand(0), OPT_ConditionOperand.LESS() , new OPT_BranchProfileOperand(), op1.copy(), tmp2.copy(), OPT_ConditionOperand.LESS(), OPT_BranchProfileOperand.unlikely())); - appendInstruction(Binary.create(INT_OR, getFlag(Flag.Overflow), getFlag(Flag.Overflow), tmp_bool.copy())); + appendInstruction(Binary.create(INT_OR, flagRegister, getFlag(Flag.Overflow), tmp_bool.copy())); } break; Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Translator.java 2007-08-21 15:29:38 UTC (rev 170) @@ -186,10 +186,10 @@ ARM_Translator translator, OperandWrapper operand) { ResolvedOperand result = new ResolvedOperand_WithShifterCarryOut(translator, operand); - return result.getValue(); + return result.getValue().copy(); } - public final OPT_Operand getValue() { + private final OPT_Operand getValue() { return value; } @@ -235,7 +235,7 @@ else { OPT_RegisterOperand tmp = translator.arm2ir.getTempInt(9); translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, translator.arm2ir.getRegister(operand.getRegister()), new OPT_IntConstantOperand(operand.getOffset()))); - value = tmp.copy(); + value = tmp; } return; @@ -382,7 +382,7 @@ curBlock.insertOut(block1); OPT_Operand carryFlag = translator.arm2ir.readCarryFlag(translator.lazy); translator.arm2ir.appendInstruction(Binary.create(INT_USHR, resultRegister, shiftedOperand.copy(), new OPT_IntConstantOperand(1))); - translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, translator.arm2ir.getTempValidation(0), carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); + translator.arm2ir.appendInstruction(IfCmp.create(INT_IFCMP, validation, carryFlag, new OPT_IntConstantOperand(1), OPT_ConditionOperand.NOT_EQUAL(), nextBlock.makeJumpTarget(), new OPT_BranchProfileOperand())); //Block 1 translator.arm2ir.setCurrentBlock(block1); @@ -519,15 +519,15 @@ //block 2 - shift < 32 && shift != 0 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand, shiftAmount.copy()) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SHR, resultRegister, shiftedOperand.copy(), shiftAmount.copy()) ); translator.arm2ir.appendInstruction(Binary.create(INT_ADD, tmp, shiftAmount.copy(), new OPT_IntConstantOperand(-1)) ); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, tmp.copy()); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); //block 3 - shift >= 32 translator.arm2ir.setCurrentBlock(block3); block3.insertOut(nextBlock); - translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand, 31); + translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), 31); translator.arm2ir.appendInstruction(Binary.create(INT_MUL, resultRegister.copyRO(), getShifterCarryOutTarget(), new OPT_IntConstantOperand(-1)) ); //creates either 0xFFFFFFFF if the bit is set, or 0 otherwise translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); @@ -563,7 +563,7 @@ //block 2 - Shift != 0 && Shift < 32 translator.arm2ir.setCurrentBlock(block2); block2.insertOut(nextBlock); - translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount) ); + translator.arm2ir.appendInstruction(Binary.create(INT_SUB, tmp, new OPT_IntConstantOperand(32), shiftAmount.copy() ) ); translator.arm2ir.appendBitTest(getShifterCarryOutTarget(), shiftedOperand.copy(), tmp.copy()); translator.arm2ir.appendInstruction(Binary.create(INT_SHL, resultRegister, shiftedOperand.copy(), shiftAmount.copy())); translator.arm2ir.appendInstruction(Goto.create(GOTO, nextBlock.makeJumpTarget())); @@ -1600,7 +1600,7 @@ @Override public void translate() { - //Call Integer.numberOfLeadingZeros() to obtain the result of this operation + //Call Integer.numberOfLeadingZeros() to obtain the result of this operation OPT_RegisterOperand result = getResultRegister(); VM_TypeReference IntegerType = VM_TypeReference @@ -1647,7 +1647,7 @@ //swap exchanges the value of a memory address with the value in a register if (!i.swapByte) { ps.memory.translateLoad32(memAddr, tmp); - ps.memory.translateStore32(memAddr, arm2ir.getRegister(i.Rm)); + ps.memory.translateStore32(memAddr.copy(), arm2ir.getRegister(i.Rm)); //according to the ARM architecture reference, the value loaded from a memory address is rotated //by the number of ones in the first two bits of the address @@ -1659,8 +1659,8 @@ arm2ir.appendRotateRight(result, tmp.copy(), rotation.copy()); } else { - ps.memory.translateLoadUnsigned8(memAddr.copy(), tmp); - ps.memory.translateStore8(memAddr, arm2ir.getRegister(i.Rm)); + ps.memory.translateLoadUnsigned8(memAddr, tmp); + ps.memory.translateStore8(memAddr.copy(), arm2ir.getRegister(i.Rm)); arm2ir.appendInstruction(Move.create(INT_MOVE, result, tmp.copy())); } } @@ -1959,7 +1959,7 @@ //set the correct processor mode (thumb or not) OPT_Instruction s = createCallToRegisters("setThumbMode", "(Z)V", 1); - Call.setParam(s, 1, enableThumb); + Call.setParam(s, 1, enableThumb.copy()); arm2ir.appendCustomCall(s); //jump to the target address. Because we might have switched to thumb mode, we are @@ -1999,7 +1999,7 @@ arm2ir.appendInstruction(Binary.create(INT_MUL, tmp, operand1, operand2)); OPT_Operand operand3 = arm2ir.getRegister(i.Rn); - arm2ir.appendInstruction(Binary.create(INT_ADD, result.copyRO(), tmp.copy(), operand3)); + arm2ir.appendInstruction(Binary.create(INT_ADD, result, tmp.copy(), operand3)); } else { arm2ir.appendInstruction(Binary.create(INT_MUL, result, operand1, operand2)); @@ -2050,7 +2050,7 @@ } //multiply the two operands - arm2ir.appendInstruction(Binary.create(LONG_MUL, result.copyRO(), operand1.copy(), operand2.copy())); + arm2ir.appendInstruction(Binary.create(LONG_MUL, result, operand1.copy(), operand2.copy())); if (i.accumulate) { //treat the accum. value as an unsigned value @@ -2247,7 +2247,7 @@ //stores the current operating mode OPT_RegisterOperand currentOperatingMode = null; - if (i.forceUserMode) { + if (i.forceUserMode) { OPT_Instruction call_getOperatingMode = createCallToRegisters("getOperatingMode", "()A", 0); currentOperatingMode = arm2ir.getTempOperatingMode(); @@ -2364,7 +2364,7 @@ else { //add the offset to the base address and write the result back into Rn OPT_Operand resolvedOffset = resolveOffset(); - arm2ir.appendInstruction(Binary.create(INT_ADD, writeBackTarget, address, resolvedOffset)); + arm2ir.appendInstruction(Binary.create(INT_ADD, writeBackTarget, address.copy(), resolvedOffset)); } } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-21 15:29:38 UTC (rev 170) @@ -14,8 +14,8 @@ public class ARM_ImageProcessSpace extends ARM_ProcessSpace { private AngelSystemCalls sysCalls; - private final int STACK_SIZE = 4096 * 100; - private final int HEAP_SIZE = 4096 * 100; + private final int STACK_SIZE = 4096 * 1000; + private final int HEAP_SIZE = 4096 * 1000; public ARM_ImageProcessSpace() { super(); Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-21 15:29:38 UTC (rev 170) @@ -695,7 +695,7 @@ unresolvedDynamicBranches.add(unresolvedInfo); setCurrentBlock(fallThrough); - appendRecordUncaughtBranch(currentPC, targetAddress.copyRO(), branchType, retAddr); + appendRecordUncaughtBranch(currentPC, targetAddress, branchType, retAddr); appendTraceExit((Laziness) lazyStateAtJump.clone(), targetAddress); } Modified: src/org/binarytranslator/generic/execution/InterpreterController.java =================================================================== --- src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-20 21:08:34 UTC (rev 169) +++ src/org/binarytranslator/generic/execution/InterpreterController.java 2007-08-21 15:29:38 UTC (rev 170) @@ -20,7 +20,8 @@ while (!ps.finished) { - Interpreter.Instruction instruction = interpreter.decode(pc); + Interpreter.Instruction instruction = interpreter.decode(pc); + //System.out.println(String.format("[%x] %s", pc, instruction.toString())); instruction.execute(); int nextInstruction = instruction.getSuccessor(pc); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-24 17:51:44
|
Revision: 173 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=173&view=rev Author: michael_baer Date: 2007-08-24 10:51:46 -0700 (Fri, 24 Aug 2007) Log Message: ----------- - Missing from last commit Modified Paths: -------------- src/org/binarytranslator/DBT_Options.java src/org/binarytranslator/Main.java src/org/binarytranslator/generic/decoder/CodeTranslator.java src/org/binarytranslator/generic/memory/CallBasedMemory.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java Modified: src/org/binarytranslator/DBT_Options.java =================================================================== --- src/org/binarytranslator/DBT_Options.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/DBT_Options.java 2007-08-24 17:51:46 UTC (rev 173) @@ -310,7 +310,7 @@ input = input.substring(pos + 1); } - if (input.length() > 1) { + if (input.length() >= 1) { state.onText(input); } } Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/Main.java 2007-08-24 17:51:46 UTC (rev 173) @@ -86,6 +86,10 @@ return; } + if (DBT_Options.buildForSunVM) { + System.err.println("WARNING: This build was done for the SUN JVM and does only support interpretation, but not binary translation. Set DBT_Options.buildForSunVM to false to build for the Jikes RVM."); + } + if (DBT.VerifyAssertions) { System.err.println("WARNING: Assertions are enabled."); } Modified: src/org/binarytranslator/generic/decoder/CodeTranslator.java =================================================================== --- src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/decoder/CodeTranslator.java 2007-08-24 17:51:46 UTC (rev 173) @@ -765,7 +765,7 @@ * supposedly a CALL or RETURN */ - boolean decision = DBT_Options.singleInstrTranslation == false && jump.type == BranchType.DIRECT_BRANCH && !shallTraceStop(); + boolean decision = DBT_Options.singleInstrTranslation == false && !shallTraceStop(); if (!decision) { @@ -778,10 +778,14 @@ return false; } - //only query the code cache if we have to - DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); - decision = (compiledTrace == null || compiledTrace.getNumberOfInstructions() < 20) ; + decision = jump.type == BranchType.DIRECT_BRANCH; + if (!decision) { + //only query the code cache if we have to + DBT_Trace compiledTrace = ps.codeCache.tryGet(targetPc); + decision = (compiledTrace != null && compiledTrace.getNumberOfInstructions() < 30); + } + if (DBT_Options.debugBranchResolution) { String text = (!decision ? "Not inlining " : "Inlining "); text += jump.type + " to 0x" + Integer.toHexString(targetPc); Modified: src/org/binarytranslator/generic/memory/CallBasedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/memory/CallBasedMemory.java 2007-08-24 17:51:46 UTC (rev 173) @@ -104,12 +104,12 @@ /** * The generation context we're translating within */ - private OPT_GenerationContext gc; + protected OPT_GenerationContext gc; /** * Register that references the memory object */ - OPT_Register memory; + protected OPT_Register memory; /** * Constructor @@ -158,7 +158,7 @@ } /** - * Generate memory prologue,... for the beignning of a trace. e.g. Loading the + * Generate memory prologue,... for the beginning of a trace. e.g. Loading the * page table into a register */ public void initTranslate(CodeTranslator helper) { @@ -202,8 +202,7 @@ if (DBT_Options.inlineCallbasedMemory) { translator.appendInlinedCall(s); } - else - { + else { s.position = gc.inlineSequence; s.bcIndex = bcIndex; translator.appendInstruction(s); @@ -395,45 +394,6 @@ } /** - * Generate the IR code for a byte store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore8(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store8, DBT_Trace.MEMORY_STORE8, addr, src); - } - - /** - * Generate the IR code for a 16bit store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore16(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store16, DBT_Trace.MEMORY_STORE16, addr, src); - } - - /** - * Generate the IR code for a 32bit store - * - * @param src - * the register that holds the value to store - * @param addr - * the address of the value to store - */ - public void translateCallBasedStore32(OPT_Operand addr, - OPT_RegisterOperand src) { - translateStore(store32, DBT_Trace.MEMORY_STORE32, addr, src); - } - - /** * Get method reference if linking a call * * @param callAddress Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:08:31 UTC (rev 172) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:51:46 UTC (rev 173) @@ -87,7 +87,7 @@ * Return the offset part of the address */ @Inline - protected int getOffset(int address) { + private static final int getOffset(int address) { return (address & (PAGE_SIZE - 1)) >>> 2; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mic...@us...> - 2007-08-27 15:14:37
|
Revision: 174 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=174&view=rev Author: michael_baer Date: 2007-08-27 08:14:38 -0700 (Mon, 27 Aug 2007) Log Message: ----------- - Added support for Big and Little Endian Applications on ARM - Added memory implementations for big endian Modified Paths: -------------- rvmroot.patch src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java Added Paths: ----------- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java Modified: rvmroot.patch =================================================================== --- rvmroot.patch 2007-08-24 17:51:46 UTC (rev 173) +++ rvmroot.patch 2007-08-27 15:14:38 UTC (rev 174) @@ -146,7 +146,7 @@ [Lorg/jikesrvm/compilers/opt/OPT_Simplifier$DefUseEffect; [Lorg/jikesrvm/compilers/opt/ir/OPT_Operator; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$AddressSize; -+[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$ByteOrder; ++[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ByteOrder; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$Header$ObjectFileType; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$SegmentRange; +[Lorg/binarytranslator/vmInterface/DummyDynamicCodeRunner; @@ -157,4 +157,6 @@ +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$Instruction$Condition; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$DataProcessing$Opcode; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$OperandWrapper$ShiftType; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Operation; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Flag; \ No newline at end of file Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,5 +1,7 @@ package org.binarytranslator.arch.arm.decoder; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; + public class ARM_Options { public enum FlagBehaviour { @@ -39,6 +41,9 @@ /** Sets the memory model that ARM shall use. */ public static MemoryModel memoryModel = MemoryModel.IntAddressed; + /** Override the byte order read from the ELF file. */ + public static ByteOrder enforcedByteOrder = null; + public static void parseOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); @@ -50,7 +55,9 @@ memoryModel = ARM_Options.MemoryModel.valueOf(value); } else if (key.equalsIgnoreCase("optimizedFlags")) { useOptimizedFlags = Boolean.parseBoolean(value); - } + } else if (key.equalsIgnoreCase("byteOrder")) { + enforcedByteOrder = ByteOrder.valueOf(value); + } else { throw new Error("Unknown ARM option: " + key); } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,9 +10,13 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.ByteAddressedBigEndianMemory; import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; +import org.binarytranslator.generic.memory.IntAddressedBigEndianMemory; import org.binarytranslator.generic.memory.IntAddressedLittleEndianMemory; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; @@ -20,11 +24,9 @@ public abstract class ARM_ProcessSpace extends ProcessSpace { - /** Registers used by this process */ public ARM_Registers registers; - /** * Debug information * @@ -38,16 +40,44 @@ } } - protected ARM_ProcessSpace() { + protected ARM_ProcessSpace(ByteOrder byteOrder) { registers = new ARM_Registers(); switch (ARM_Options.memoryModel) { case ByteAddressed: - memory = new ByteAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new ByteAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new ByteAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; case IntAddressed: - memory = new IntAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new IntAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new IntAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; default: @@ -79,12 +109,30 @@ public static ProcessSpace createProcessSpaceFromBinary(Loader loader) throws IOException { Loader.ABI abi = loader.getABI(); + + //determine the byte order for the memory implementation + ByteOrder byteOrder = ARM_Options.enforcedByteOrder; + + if (byteOrder == null) { + if (loader instanceof ELF_Loader) { + //read the byte order from the elf file + byteOrder = ((ELF_Loader)loader).getFile().getByteOrder(); + } + else { + byteOrder = ByteOrder.LittleEndian; + System.err.println("WARNING: Unable to deduce byte order from binary file. Defaulting to " + byteOrder); + } + } + else { + System.err.println("WARNING: Overriding byte order set by ELF file to " + byteOrder); + } + if (abi == Loader.ABI.ARM) { report("Creating ARM Linux ABI Process space"); - return new ARM_LinuxProcessSpace(); + return new ARM_LinuxProcessSpace(byteOrder); } else { report("Creating ARM image process space."); - return new ARM_ImageProcessSpace(); + return new ARM_ImageProcessSpace(byteOrder); } } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.InsufficientMemoryException; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { @@ -17,11 +18,8 @@ private final int STACK_SIZE = 4096 * 1000; private final int HEAP_SIZE = 4096 * 1000; - public ARM_ImageProcessSpace() { - super(); - - //make sure that pages of memory are automatically mapped in as they are requested. - //memory = new AutoMappingMemory(memory); + public ARM_ImageProcessSpace(ByteOrder byteOrder) { + super(byteOrder); } private int allocateFreeMemoryArea(int stackSize) throws InsufficientMemoryException Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.os.abi.linux.LinuxSystemCalls; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_LinuxProcessSpace extends ARM_ProcessSpace { @@ -31,7 +32,9 @@ */ private int[] auxVector; - public ARM_LinuxProcessSpace() { + public ARM_LinuxProcessSpace(ByteOrder byteOrder) { + super(byteOrder); + sysCallGenerator = new Legacy(this); sysCalls = new ARM_LinuxSystemCalls(this, sysCallGenerator); } Added: src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,550 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; + +/** + * ByteAddressedMemory: + * + * Memory is arrays of bytes, no endian conversion is performed. + * + * The string helo followed by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address| + * ----------------- + * .........07 | ca| + * .........06 | fe| + * .........05 | ba| + * .........04 | be| + * .........03 |'o'| + * .........02 |'l'| + * .........01 |'e'| + * .........00 |'H'| + * </pre> + */ +public class ByteAddressedBigEndianMemory extends CallBasedMemory { + + /** The size of a single page in bytes. */ + private static final int PAGE_SIZE = 4096; + + /** Bits in offset */ + private static final int OFFSET_BITS = 12; + + /** The number of pages */ + private static final int NUM_PAGES = 0x100000; + + /** The maximum amount of RAM available */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** The memory backing store */ + private byte readableMemory[][]; + private byte writableMemory[][]; + private byte executableMemory[][]; + + /** Do we have more optimal nio mmap operation? */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public ByteAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the name of the over-riding class + */ + protected ByteAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : ByteAddressedBigEndianMemory.class); + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + + if (DBT_Options.debugMemory) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate pages + readableMemory[pte + i] = read ? pages[i] : null; + writableMemory[pte + i] = write ? pages[i] : null; + executableMemory[pte + i] = exec ? pages[i] : null; + } + + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + + readableMemory[pte + i] = read ? page : null; + writableMemory[pte + i] = write ? page : null; + executableMemory[pte + i] = exec ? page : null; + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate page + if (read && write) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + writableMemory[pte + i] = readableMemory[pte + i]; + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (read) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (exec) { + executableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + } else { + throw new Error("Unable to map address 0x" + + Integer.toHexString(addr) + " with permissions " + + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + } + } + return addr; + } catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private byte[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + final public int loadSigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)]; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + final public int loadUnsigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + return (loadSigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + return (loadUnsigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + try { + return (loadSigned8(addr) << 24) | (loadUnsigned8(addr + 1) << 16) + | (loadUnsigned8(addr + 2) << 8) | loadUnsigned8(addr + 3); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + if (DBT_Options.debugMemory) + System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) + + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); + return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + return (loadInstruction8(addr) << 24) + | (loadInstruction8(addr + 1) << 16) + | (loadInstruction8(addr + 2) << 8) | loadInstruction8(addr + 3); + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public final void store8(int addr, int value) { + if (DBT_Options.debugMemory) + System.err.println("Store8 address: 0x" + Integer.toHexString(addr) + + " val: 0x" + Integer.toHexString(value & 0xFF)); + writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + store8(addr, value >> 8); + store8(addr + 1, value); + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + try { + store8(addr, value >> 24); + store8(addr + 1, value >> 16); + store8(addr + 2, value >> 8); + store8(addr + 3, value); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + byte[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + @Override + public int loadInstruction16(int addr) { + return (loadInstruction8(addr) << 8) | loadInstruction8(addr + 1); + } +} Added: src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,669 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; +import org.vmmagic.pragma.Inline; + +/** + * IntAddressedMemory: + * + * Memory is arrays of ints, no endian conversion is performed. + * + * The string helloworld following by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address + * Int Address | 0 | 1 | 2 | 3 | + * ----------------------------- + * .........0c | ca| fe| ba| be| + * .........08 |'l'|'d'| \n| \0| + * .........04 |'o'|'W'|'o'|'r'| + * .........00 |'H'|'e'|'l'|'l'| + * </pre> + */ +public class IntAddressedBigEndianMemory extends CallBasedMemory { + /** + * The size of pages + */ + protected static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + protected static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + protected static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private int readableMemory[][]; + + private int writableMemory[][]; + + private int executableMemory[][]; + + /** + * Constructor - used when this is the instatiated class + */ + public IntAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the type of the over-riding class + */ + protected IntAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : IntAddressedBigEndianMemory.class); + readableMemory = new int[NUM_PAGES][]; + writableMemory = new int[NUM_PAGES][]; + executableMemory = new int[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + @Inline + private static final int getOffset(int address) { + return (address & (PAGE_SIZE - 1)) >>> 2; + } + + /** + * Return the page table entry part of the address + */ + @Inline + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check that the address is page aligned + if ((addr % PAGE_SIZE) != 0) { + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); + } + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Create memory + int pages[][] = new int[num_pages][PAGE_SIZE / 4]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugRuntime) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + readableMemory[pte+i] = read ? pages[i] : null; + writableMemory[pte+i] = write ? pages[i] : null; + executableMemory[pte+i] = exec ? pages[i] : null; + } + return addr; + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private int[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + int[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + /** + * Read an int from RandomAccessFile ensuring that a byte swap isn't performed + * + * @param file + * file to read from + * @return native endian read int + */ + protected int readInt(RandomAccessFile file) throws java.io.IOException { + + return file.readByte() << 24 | (file.readUnsignedByte() << 16) + | (file.readUnsignedByte() << 8) | (file.readUnsignedByte()); + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public final int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + if (DBT_Options.debugRuntime) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + addr = map(addr, len, read, write, exec); + + try { + file.seek(offset); + for (int i = 0; i < len; i += 4) { + + int[] page = getPage(getPTE(addr + i)); + page[getOffset(addr + i)] = readInt(file); + } + + return addr; + + } + catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public final void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Perform a 32bit load where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAligned32(int addr) { + return readableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a 32bit load where addr is word aligned and executable + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAlignedInstruction32(int addr) { + return executableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned8(int addr) { + return (loadWordAligned32(addr) << ((addr & 0x3) << 3)) >> 24; + // switch(addr & 3) { + // default: + // return (loadWordAligned32(addr) << 24) >> 24; + // case 1: + // return (loadWordAligned32(addr) << 16) >> 24; + // case 2: + // return (loadWordAligned32(addr) << 8) >> 24; + // case 3: + // return loadWordAligned32(addr) >> 24; + // } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned8(int addr) { + return (loadWordAligned32(addr) >> ((3 - (addr & 3)) << 3)) & 0xFF; + // switch(addr & 3) { + // default: + // return loadWordAligned32(addr) & 0xFF; + // case 1: + // return (loadWordAligned32(addr) >> 8) & 0xFF; + // case 2: + // return (loadWordAligned32(addr) >> 16) & 0xFF; + // case 3: + // return loadWordAligned32(addr) >>> 24; + // } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >> 16; + case 1: + return (loadWordAligned32(addr) << 8) >> 16; + case 2: + return (loadWordAligned32(addr) << 16) >> 16; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 24) >> 16) + | (loadWordAligned32(addr + 1) >>> 24); + } + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >>> 16; + case 1: + return (loadWordAligned32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAligned32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 8) & 0xFF00) + | loadWordAligned32(addr + 1) >>> 24; + } + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 3) >>> 24) + | (loadWordAligned32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 2) >>> 16) + | (loadWordAligned32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 1) >>> 8) + | (loadWordAligned32(addr) << 24); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 24; + case 1: + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFF; + case 2: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFF; + case 3: + return loadWordAlignedInstruction32(addr) & 0xFF; + } + } + + @Override + public int loadInstruction16(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 16; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAlignedInstruction32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr) << 8) & 0xFF00) + | (loadWordAlignedInstruction32(addr + 1) >>> 25); + } + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 3) >>> 24) + | (loadWordAlignedInstruction32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 2) >>> 16) + | (loadWordAlignedInstruction32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 1) >>> 8) + | (loadWordAlignedInstruction32(addr) << 24); + } + } + + /** + * Perform a 32bit aligned store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + final protected void storeWordAligned32(int addr, int value) { + writableMemory[getPTE(addr)][getOffset(addr)] = value; + } + + /** + * Perform a 32bit load, from writable memory, where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + final protected int loadWordAligned32forWrite(int addr) { + return writableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store8(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF00FFFF) + | ((value & 0xFF) << 16)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF00FF) + | ((value & 0xFF) << 8)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value & 0xFF)); + break; + } + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF0000FF) + | ((value & 0xFFFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value & 0xFFFF)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | ((value >> 8) & 0xFF)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x00FFFFFF) + | (value << 24)); + break; + } + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, value); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF000000) + | (value >>> 8)); + storeWordAligned32(addr + 3, + (loadWordAligned32forWrite(addr + 3) & 0x00FFFFFF) | (value << 24)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value >>> 16)); + storeWordAligned32(addr + 2, + (loadWordAligned32forWrite(addr + 2) & 0x0000FFFF) | (value << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value >>> 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x000000FF) | (value << 8)); + break; + } + } +} Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -13,7 +13,6 @@ import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.fault.SegmentationFault; -import org.jikesrvm.VM_Configuration; import org.vmmagic.pragma.Inline; /** @@ -283,12 +282,8 @@ * @return native endian read int */ protected int readInt(RandomAccessFile file) throws java.io.IOException { - if (VM_Configuration.BuildForPowerPC) { - return file.readInt(); // NB this will always read in big-endian format - } else { - return file.readUnsignedByte() | (file.readUnsignedByte() << 8) - | (file.readUnsignedByte() << 16) | (file.readByte() << 24); - } + return file.readUnsignedByte() | (file.readUnsignedByte() << 8) + | (file.readUnsignedByte() << 16) | (file.readByte() << 24); } /** Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-27 15:14:38 UTC (rev 174) @@ -22,7 +22,23 @@ import org.binarytranslator.generic.os.process.ProcessSpace; public class ELF_File { + + /** Represents accepted ELF byte orders. */ + public enum ByteOrder implements IdentifiedEnum { + LittleEndian(1), + BigEndian(2); + + private int identifier; + + private ByteOrder(int identifier) { + this.identifier = identifier; + } + public int getIdentifier() { + return identifier; + } + } + /** Wrapper class used for reading the ELF file with the required endianness */ private BinaryReader reader; @@ -31,6 +47,10 @@ /** Program segment headers */ private SegmentHeader segmentHeaders[]; + + public ByteOrder getByteOrder() { + return header.byteOrder; + } /** * Debug information @@ -60,9 +80,9 @@ * @return * An ELF_BinaryReader, that hides the details of the byte order. */ - public static BinaryReader create(ELF_Identity.ByteOrder byteOrder, RandomAccessFile file) { + public static BinaryReader create(ByteOrder byteOrder, RandomAccessFile file) { - if (byteOrder == ELF_Identity.ByteOrder.BigEndian) + if (byteOrder == ByteOrder.BigEndian) return new NonSwappingReader(file); else return new ByteSwappingReader(file); @@ -296,22 +316,6 @@ } } - /** Represents accepted ELF byte orders. */ - private enum ByteOrder implements IdentifiedEnum { - LittleEndian(1), - BigEndian(2); - - private int identifier; - - private ByteOrder(int identifier) { - this.identifier = identifier; - } - - public int getIdentifier() { - return identifier; - } - } - /* Symbolic names for the most widely used ABIs. This is not an enum, because the list isn't complete. */ private static final byte ELFOSABI_SYSTEMV = 0; private static final byte ELFOSABI_HPUX = 1; @@ -334,13 +338,13 @@ private static final byte ELF_MAGIC_VALUE[] = { 0x7f, 'E', 'L','F' }; /** Specifies the size of an address within this elf.*/ - private AddressSize addressSize; + AddressSize addressSize; /** The byte order used by this elf.*/ - private ByteOrder byteOrder; + ByteOrder byteOrder; /** The ABI that is used by this ELF.*/ - private byte abi; + byte abi; /** * Construct/read ELF identity Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,7 +1,6 @@ package org.binarytranslator.generic.os.loader.elf; import java.io.IOException; - import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |