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. |