// PART OF THE MACHINE SIMULATION. DO NOT CHANGE. package nachos.machine; import java.io.EOFException; /** * A COFF (common object file format) loader. */ public class Coff { /** * Allocate a new Coff object. */ protected Coff() { file = null; entryPoint = 0; sections = null; } /** * Load the COFF executable in the specified file. * * <p> * Notes: * <ol> * <li>If the constructor returns successfully, the file becomes the * property of this loader, and should not be accessed any further. * <li>The autograder expects this loader class to be used. Do not load * sections through any other mechanism. * <li>This loader will verify that the file is backed by a file system, * by asserting that read() operations take non-zero simulated time to * complete. Do not supply a file backed by a simulated cache (the primary * purpose of this restriction is to prevent sections from being loaded * instantaneously while handling page faults). * </ol> * * @param file the file containing the executable. * @exception EOFException if the executable is corrupt. */ public Coff(OpenFile file) throws EOFException { this.file = file; Coff coff = Machine.autoGrader().createLoader(file); if (coff != null) { this.entryPoint = coff.entryPoint; this.sections = coff.sections; } else { byte[] headers = new byte[headerLength+aoutHeaderLength]; if (file.length() < headers.length) { Lib.debug(dbgCoff, "\tfile is not executable"); throw new EOFException(); } Lib.strictReadFile(file, 0, headers, 0, headers.length); int magic = Lib.bytesToUnsignedShort(headers, 0); int numSections = Lib.bytesToUnsignedShort(headers, 2); int optionalHeaderLength = Lib.bytesToUnsignedShort(headers, 16); int flags = Lib.bytesToUnsignedShort(headers, 18); entryPoint = Lib.bytesToInt(headers, headerLength+16); if (magic != 0x0162) { Lib.debug(dbgCoff, "\tincorrect magic number"); throw new EOFException(); } if (numSections < 2 || numSections > 10) { Lib.debug(dbgCoff, "\tbad section count"); throw new EOFException(); } if ((flags & 0x0003) != 0x0003) { Lib.debug(dbgCoff, "\tbad header flags"); throw new EOFException(); } int offset = headerLength + optionalHeaderLength; sections = new CoffSection[numSections]; for (int s=0; s<numSections; s++) { int sectionEntryOffset = offset + s*CoffSection.headerLength; try { sections[s] = new CoffSection(file, this, sectionEntryOffset); } catch (EOFException e) { Lib.debug(dbgCoff, "\terror loading section " + s); throw e; } } } } /** * Return the number of sections in the executable. * * @return the number of sections in the executable. */ public int getNumSections() { return sections.length; } /** * Return an object that can be used to access the specified section. Valid * section numbers include <tt>0</tt> through <tt>getNumSections() - * 1</tt>. * * @param sectionNumber the section to select. * @return an object that can be used to access the specified section. */ public CoffSection getSection(int sectionNumber) { Lib.assertTrue(sectionNumber >= 0 && sectionNumber < sections.length); return sections[sectionNumber]; } /** * Return the program entry point. This is the value that to which the PC * register should be initialized to before running the program. * * @return the program entry point. */ public int getEntryPoint() { Lib.assertTrue(file != null); return entryPoint; } /** * Close the executable file and release any resources allocated by this * loader. */ public void close() { file.close(); sections = null; } private OpenFile file; /** The virtual address of the first instruction of the program. */ protected int entryPoint; /** The sections in this COFF executable. */ protected CoffSection sections[]; private static final int headerLength = 20; private static final int aoutHeaderLength = 28; private static final char dbgCoff = 'c'; }