p1/machine/Coff.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';
}