package com.oracle.objectfile.pecoff;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.oracle.objectfile.BuildDependency;
import com.oracle.objectfile.ElementImpl;
import com.oracle.objectfile.LayoutDecision;
import com.oracle.objectfile.LayoutDecisionMap;
import com.oracle.objectfile.ObjectFile;
import com.oracle.objectfile.SymbolTable;
import com.oracle.objectfile.debuginfo.DebugInfoProvider;
import com.oracle.objectfile.io.AssemblyBuffer;
import com.oracle.objectfile.io.OutputAssembler;
import com.oracle.objectfile.pecoff.PECoff.IMAGE_FILE_HEADER;
import com.oracle.objectfile.pecoff.PECoff.IMAGE_SECTION_HEADER;
import com.oracle.objectfile.pecoff.cv.CVDebugInfo;
import com.oracle.objectfile.pecoff.cv.CVSymbolSectionImpl;
import com.oracle.objectfile.pecoff.cv.CVTypeSectionImpl;
public class PECoffObjectFile extends ObjectFile {
private static ByteOrder byteOrder;
private PECoffMachine machine = PECoffMachine.getSystemNativeValue();
private PECoffHeader ;
private SectionHeaderTable sht;
private PECoffSymtab symtab;
private PECoffDirectiveSection directives;
private boolean runtimeDebugInfoGeneration;
private PECoffObjectFile(int pageSize, boolean runtimeDebugInfoGeneration) {
super(pageSize);
this.runtimeDebugInfoGeneration = runtimeDebugInfoGeneration;
header = new PECoffHeader("PECoffHeader");
sht = new SectionHeaderTable();
symtab = createSymbolTable();
directives = new PECoffDirectiveSection(".drectve", 1);
}
public PECoffObjectFile(int pageSize) {
this(pageSize, false);
}
@Override
public Format getFormat() {
return Format.PECOFF;
}
@Override
protected PECoffSymtab createSymbolTable() {
String name = ".symtab";
PECoffSymtab st = (PECoffSymtab) elementForName(".symtab");
if (st == null) {
st = new PECoffSymtab(this, name);
}
return st;
}
@Override
public Symbol createDefinedSymbol(String name, Element baseSection, long position, int size, boolean isCode, boolean isGlobal) {
PECoffSymtab st = createSymbolTable();
return st.newDefinedEntry(name, (Section) baseSection, position, size, isGlobal, isCode);
}
@Override
public Symbol createUndefinedSymbol(String name, int size, boolean isCode) {
PECoffSymtab st = createSymbolTable();
return st.newUndefinedEntry(name, isCode);
}
@Override
protected Segment getOrCreateSegment(String maybeSegmentName, String sectionName, boolean writable, boolean executable) {
return null;
}
@Override
public PECoffUserDefinedSection newUserDefinedSection(Segment segment, String name, int alignment, ElementImpl impl) {
PECoffUserDefinedSection userDefined = new PECoffUserDefinedSection(this, name, alignment, impl);
assert userDefined.getImpl() == impl;
if (segment != null) {
getOrCreateSegment(segment.getName(), name, true, false).add(userDefined);
}
if (impl != null) {
impl.setElement(userDefined);
}
return userDefined;
}
@Override
public PECoffProgbitsSection newProgbitsSection(Segment segment, String name, int alignment, boolean writable, boolean executable, ProgbitsSectionImpl impl) {
EnumSet<PECoffSectionFlag> flags = EnumSet.noneOf(PECoffSectionFlag.class);
flags.add(PECoffSectionFlag.READ);
if (executable) {
flags.add(PECoffSectionFlag.EXECUTE);
flags.add(PECoffSectionFlag.CODE);
} else {
flags.add(PECoffSectionFlag.INITIALIZED_DATA);
}
if (writable) {
flags.add(PECoffSectionFlag.WRITE);
}
PECoffProgbitsSection progbits = new PECoffProgbitsSection(this, name, alignment, impl, flags);
impl.setElement(progbits);
return progbits;
}
@Override
public PECoffNobitsSection newNobitsSection(Segment segment, String name, NobitsSectionImpl impl) {
PECoffNobitsSection nobits = new PECoffNobitsSection(this, name, impl);
impl.setElement(nobits);
return nobits;
}
public PECoffSection getSectionByIndex(int i) {
return (PECoffSection) elements.get(elements.sectionIndexToElementIndex(i - 1));
}
public int getIndexForSection(PECoffSection s) {
return elements.elementIndexToSectionIndex(elements.indexOf(s)) + 1;
}
@Override
protected boolean elementsCanSharePage(Element s1, Element s2, int off1, int off2) {
if (s1 instanceof PECoffSection && s2 instanceof PECoffSection) {
PECoffSection es1 = (PECoffSection) s1;
PECoffSection es2 = (PECoffSection) s2;
boolean flagsCompatible = PECoffSectionFlag.getMemSegmentFlags(es1.getFlags()) == PECoffSectionFlag.getMemSegmentFlags(es2.getFlags());
return flagsCompatible && super.elementsCanSharePage(es1, es2, off1, off2);
} else if (s1 instanceof PECoffSection || s2 instanceof PECoffSection) {
return false;
} else {
assert !(s1 instanceof PECoffSection);
assert !(s2 instanceof PECoffSection);
return true;
}
}
public List<PECoffSection> getPECoffSections() {
List<PECoffSection> sections = new ArrayList<>(elements.sectionsCount());
Iterator<Section> it = elements.sectionsIterator();
while (it.hasNext()) {
PECoffSection pe = (PECoffSection) it.next();
sections.add(pe);
}
return sections;
}
public abstract class PECoffSection extends ObjectFile.Section {
EnumSet<PECoffSectionFlag> flags;
int sectionID;
Object relocEntries;
public PECoffSection(String name) {
this(name, EnumSet.noneOf(PECoffSectionFlag.class));
}
public PECoffSection(String name, EnumSet<PECoffSectionFlag> flags) {
this(name, getWordSizeInBytes(), flags, -1);
}
public PECoffSection(String name, int alignment, EnumSet<PECoffSectionFlag> flags, int sectionIndex) {
super(name, alignment, (sectionIndex == -1) ? -1 : elements.sectionIndexToElementIndex(sectionIndex - 1));
this.flags = flags;
}
@Override
public PECoffObjectFile getOwner() {
return PECoffObjectFile.this;
}
@Override
public boolean isLoadable() {
if (getImpl() == this) {
return flags.contains(PECoffSectionFlag.READ);
}
boolean implIsLoadable = getImpl().isLoadable();
assert implIsLoadable == flags.contains(PECoffSectionFlag.READ);
return implIsLoadable;
}
@Override
public boolean isReferenceable() {
if (getImpl() == this) {
return isLoadable();
}
return getImpl().isReferenceable();
}
public PECoffSection getLinkedSection() {
return null;
}
public long getLinkedInfo() {
return 0;
}
public int getEntrySize() {
return 0;
}
public EnumSet<PECoffSectionFlag> getFlags() {
return flags;
}
public void setFlags(EnumSet<PECoffSectionFlag> flags) {
this.flags = flags;
}
public void setSectionID(int id) {
this.sectionID = id;
}
public int getSectionID() {
return this.sectionID;
}
public void setRelocEntries(Object entries) {
this.relocEntries = entries;
}
public Object getRelocEntries() {
return this.relocEntries;
}
}
public class extends ObjectFile.Header {
PECoffHeaderStruct ;
public (String name) {
super(name);
hdr = new PECoffHeaderStruct();
}
@Override
public Iterable<BuildDependency> (Map<Element, LayoutDecisionMap> decisions) {
HashSet<BuildDependency> dependencies = new HashSet<>();
LayoutDecision ourContent = decisions.get(this).getDecision(LayoutDecision.Kind.CONTENT);
LayoutDecision ourOffset = decisions.get(this).getDecision(LayoutDecision.Kind.OFFSET);
LayoutDecision ourSize = decisions.get(this).getDecision(LayoutDecision.Kind.SIZE);
LayoutDecision shtSize = decisions.get(sht).getDecision(LayoutDecision.Kind.SIZE);
LayoutDecision symtOffset = decisions.get(symtab).getDecision(LayoutDecision.Kind.OFFSET);
LayoutDecision symtSize = decisions.get(symtab).getDecision(LayoutDecision.Kind.SIZE);
dependencies.add(BuildDependency.createOrGet(ourOffset, ourSize));
dependencies.add(BuildDependency.createOrGet(ourContent, shtSize));
dependencies.add(BuildDependency.createOrGet(ourContent, symtOffset));
dependencies.add(BuildDependency.createOrGet(ourContent, symtSize));
return dependencies;
}
@Override
public byte[] (Map<Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) {
int sectSize = (int) alreadyDecided.get(sht).getDecidedValue(LayoutDecision.Kind.SIZE);
hdr.setSectionCount(sectSize / IMAGE_SECTION_HEADER.totalsize);
hdr.setSymbolOff((int) alreadyDecided.get(symtab).getDecidedValue(LayoutDecision.Kind.OFFSET));
hdr.setSymbolCount(symtab.getSymbolCount());
return hdr.getArray();
}
@Override
public int (Map<Element, LayoutDecisionMap> alreadyDecided, int offsetHint) {
return 0;
}
@Override
public int (Map<Element, LayoutDecisionMap> alreadyDecided, int sizeHint) {
return IMAGE_FILE_HEADER.totalsize;
}
}
public enum PECoffSectionFlag implements ValueEnum {
CODE(IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_CODE),
INITIALIZED_DATA(IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_INITIALIZED_DATA),
UNINITIALIZED_DATA(IMAGE_SECTION_HEADER.IMAGE_SCN_CNT_UNINITIALIZED_DATA),
READ(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ),
WRITE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE),
EXECUTE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE),
DISCARDABLE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_DISCARDABLE),
LINKER(IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE);
private final int value;
PECoffSectionFlag(int value) {
this.value = value;
}
@Override
public long value() {
return value;
}
public static long getMemSegmentFlags(EnumSet<PECoffSectionFlag> flags) {
long out = PECoffSectionFlag.READ.value();
if (flags.contains(PECoffSectionFlag.WRITE)) {
out |= PECoffSectionFlag.WRITE.value();
}
if (flags.contains(PECoffSectionFlag.EXECUTE)) {
out |= PECoffSectionFlag.EXECUTE.value();
}
return out;
}
}
public class extends ObjectFile.Element {
@Override
public ElementImpl () {
return this;
}
@Override
public boolean () {
return false;
}
public () {
super(".secthdrtab");
}
@Override
public Iterable<BuildDependency> (Map<Element, LayoutDecisionMap> decisions) {
HashSet<BuildDependency> deps = ObjectFile.defaultDependencies(decisions, this);
LayoutDecision ourOffset = decisions.get(this).getDecision(LayoutDecision.Kind.OFFSET);
LayoutDecision ourContent = decisions.get(this).getDecision(LayoutDecision.Kind.CONTENT);
LayoutDecision hdrOffset = decisions.get(header).getDecision(LayoutDecision.Kind.OFFSET);
LayoutDecision hdrSize = decisions.get(header).getDecision(LayoutDecision.Kind.SIZE);
deps.add(BuildDependency.createOrGet(ourOffset, hdrOffset));
deps.add(BuildDependency.createOrGet(ourOffset, hdrSize));
LayoutDecision prevOffset = null;
LayoutDecision prevSize = null;
int sectionID = 0;
for (Section s : getSections()) {
assert s instanceof PECoffSection;
PECoffSection pecoffS = (PECoffSection) s;
pecoffS.setSectionID(sectionID++);
LayoutDecision nextOffset = decisions.get(s).getDecision(LayoutDecision.Kind.OFFSET);
if (prevOffset != null) {
deps.add(BuildDependency.createOrGet(nextOffset, prevOffset));
}
LayoutDecision nextSize = decisions.get(s).getDecision(LayoutDecision.Kind.SIZE);
if (prevSize != null) {
deps.add(BuildDependency.createOrGet(nextOffset, prevSize));
}
deps.add(BuildDependency.createOrGet(ourContent, nextOffset));
deps.add(BuildDependency.createOrGet(ourContent, nextSize));
prevOffset = nextOffset;
prevSize = nextSize;
}
PECoffRelocationTable reloctable = getRelocationTable();
LayoutDecision relocOffset = decisions.get(reloctable).getDecision(LayoutDecision.Kind.OFFSET);
LayoutDecision relocSize = decisions.get(reloctable).getDecision(LayoutDecision.Kind.SIZE);
deps.add(BuildDependency.createOrGet(relocOffset, prevOffset));
deps.add(BuildDependency.createOrGet(relocOffset, prevSize));
deps.add(BuildDependency.createOrGet(ourContent, relocOffset));
deps.add(BuildDependency.createOrGet(ourContent, relocSize));
LayoutDecision symtabOffset = decisions.get(symtab).getDecision(LayoutDecision.Kind.OFFSET);
deps.add(BuildDependency.createOrGet(symtabOffset, relocOffset));
deps.add(BuildDependency.createOrGet(symtabOffset, relocSize));
return deps;
}
@Override
public int (Map<Element, LayoutDecisionMap> alreadyDecided, int sizeHint) {
return (elements.sectionsCount()) * IMAGE_SECTION_HEADER.totalsize;
}
@Override
public byte[] (Map<Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) {
PECoffRelocationTable rt = (PECoffRelocationTable) elementForName(".reloctab");
OutputAssembler out = AssemblyBuffer.createOutputAssembler(getByteOrder());
int sectionIndex = 0;
for (Section s : getSections()) {
PECoffSection es = (PECoffSection) s;
int align = es.getAlignment() >= 1024 ? 16 : es.getAlignment();
PECoffSectionStruct ent = new PECoffSectionStruct(
nameForElement(s),
(int) ObjectFile.flagSetAsLong(es.getFlags()),
align,
sectionIndex + 1);
ent.setOffset((int) alreadyDecided.get(es).getDecidedValue(LayoutDecision.Kind.OFFSET));
int sectionSize = (int) alreadyDecided.get(es).getDecidedValue(LayoutDecision.Kind.SIZE);
if (sectionSize == 0) {
sectionSize = es.getMemSize(alreadyDecided);
}
ent.setSize(sectionSize);
if (es.getFlags().contains(PECoffSectionFlag.READ) && runtimeDebugInfoGeneration) {
ent.setVirtualAddress((int) alreadyDecided.get(es).getDecidedValue(LayoutDecision.Kind.VADDR));
} else {
ent.setVirtualAddress(0);
}
int relocBaseOffset = ((int) alreadyDecided.get(rt).getDecidedValue(LayoutDecision.Kind.OFFSET));
int relocCount = rt.getRelocCount(sectionIndex);
if (relocCount > 0) {
ent.setRelcount(relocCount);
ent.setReloff(relocBaseOffset + rt.getRelocOffset(sectionIndex));
}
out.align(PECoffSectionStruct.getShdrAlign());
out.writeBlob(ent.getArray());
sectionIndex++;
}
return out.getBlob();
}
@Override
public LayoutDecisionMap (LayoutDecisionMap copyingIn) {
return defaultDecisions(this, copyingIn);
}
@Override
public int (Map<Element, LayoutDecisionMap> alreadyDecided, int offsetHint) {
return IMAGE_FILE_HEADER.totalsize;
}
@Override
public int (Map<Element, LayoutDecisionMap> alreadyDecided, int vaddrHint) {
return defaultGetOrDecideVaddr(alreadyDecided, this, vaddrHint);
}
}
public class PECoffDirectiveSection extends PECoffObjectFile.PECoffSection {
public PECoffDirectiveSection(String name, int alignment) {
super(name, alignment, EnumSet.of(PECoffSectionFlag.LINKER), -1);
}
@Override
public ElementImpl getImpl() {
return directives;
}
@Override
public int getOrDecideOffset(Map<Element, LayoutDecisionMap> alreadyDecided, int offsetHint) {
return IMAGE_FILE_HEADER.totalsize + ((elements.sectionsCount()) * IMAGE_SECTION_HEADER.totalsize);
}
@Override
public int getOrDecideVaddr(Map<Element, LayoutDecisionMap> alreadyDecided, int vaddrHint) {
return ObjectFile.defaultGetOrDecideVaddr(alreadyDecided, this, vaddrHint);
}
@Override
public LayoutDecisionMap getDecisions(LayoutDecisionMap copyingIn) {
return ObjectFile.defaultDecisions(this, copyingIn);
}
@Override
public Iterable<BuildDependency> getDependencies(Map<Element, LayoutDecisionMap> decisions) {
return ObjectFile.defaultDependencies(decisions, this);
}
@Override
public byte[] getOrDecideContent(Map<Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) {
return symtab.getDirectiveArray();
}
@Override
public int getOrDecideSize(Map<Element, LayoutDecisionMap> alreadyDecided, int sizeHint) {
return symtab.getDirectiveSize();
}
}
@Override
public Set<Segment> getSegments() {
return new HashSet<>();
}
@Override
public ByteOrder getByteOrder() {
return byteOrder;
}
@Override
public void setByteOrder(ByteOrder byteorder) {
byteOrder = byteorder;
}
public static ByteOrder getTargetByteOrder() {
return byteOrder;
}
@Override
public int getWordSizeInBytes() {
return 8;
}
@Override
public boolean shouldRecordDebugRelocations() {
return true;
}
public PECoffMachine getMachine() {
return machine;
}
public PECoffRelocationTable getOrCreateRelocSection(PECoffSymtab syms, boolean withExplicitAddends) {
Element el = elementForName(".reloctab");
PECoffRelocationTable rs;
if (el == null) {
rs = new PECoffRelocationTable(this, ".reloctab", syms, withExplicitAddends);
} else if (el instanceof PECoffRelocationTable) {
rs = (PECoffRelocationTable) el;
} else {
throw new IllegalStateException("section exists but is not an PECoffRelocationTable");
}
return rs;
}
@Override
public SymbolTable getSymbolTable() {
return (SymbolTable) elementForName(".symtab");
}
public PECoffRelocationTable getRelocationTable() {
return (PECoffRelocationTable) elementForName(".reloctab");
}
@Override
protected int getMinimumFileSize() {
return 0;
}
@Override
public Section newDebugSection(String name, ElementImpl impl) {
PECoffSection coffSection = (PECoffSection) super.newDebugSection(name, impl);
coffSection.getFlags().add(PECoffSectionFlag.DISCARDABLE);
coffSection.getFlags().add(PECoffSectionFlag.READ);
coffSection.getFlags().add(PECoffSectionFlag.INITIALIZED_DATA);
return coffSection;
}
@Override
public void installDebugInfo(DebugInfoProvider debugInfoProvider) {
CVDebugInfo cvDebugInfo = new CVDebugInfo(getByteOrder());
CVSymbolSectionImpl cvSymbolSectionImpl = cvDebugInfo.getCVSymbolSection();
CVTypeSectionImpl cvTypeSectionImpl = cvDebugInfo.getCVTypeSection();
newDebugSection(cvSymbolSectionImpl.getSectionName(), cvSymbolSectionImpl);
newDebugSection(cvTypeSectionImpl.getSectionName(), cvTypeSectionImpl);
cvSymbolSectionImpl.getOrCreateRelocationElement(false);
cvTypeSectionImpl.getOrCreateRelocationElement(false);
cvDebugInfo.installDebugInfo(debugInfoProvider);
}
}