152 lines
4.3 KiB
Java
152 lines
4.3 KiB
Java
// 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';
|
|
}
|