use of com.oracle.svm.hosted.image.sources.SourceManager in project graal by oracle.
the class MethodPointerInvalidHandlerFeature method build.
/**
* Create the image sections for code, constants, and the heap.
*/
@Override
@SuppressWarnings("try")
public void build(String imageName, DebugContext debug) {
try (DebugContext.Scope buildScope = debug.scope("NativeImage.build")) {
final CGlobalDataFeature cGlobals = CGlobalDataFeature.singleton();
long roSectionSize = codeCache.getAlignedConstantsSize();
long rwSectionSize = ConfigurationValues.getObjectLayout().alignUp(cGlobals.getSize());
ImageHeapLayoutInfo heapLayout = heap.getLayouter().layout(heap, objectFile.getPageSize());
// after this point, the layout is final and must not be changed anymore
assert !hasDuplicatedObjects(heap.getObjects()) : "heap.getObjects() must not contain any duplicates";
imageHeapSize = heapLayout.getImageHeapSize();
// Text section (code)
final int textSectionSize = codeCache.getCodeCacheSize();
final RelocatableBuffer textBuffer = new RelocatableBuffer(textSectionSize, objectFile.getByteOrder());
final NativeTextSectionImpl textImpl = NativeTextSectionImpl.factory(textBuffer, objectFile, codeCache);
textSection = objectFile.newProgbitsSection(SectionName.TEXT.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), false, true, textImpl);
boolean writable = SubstrateOptions.ForceNoROSectionRelocations.getValue();
// Read-only data section
final RelocatableBuffer roDataBuffer = new RelocatableBuffer(roSectionSize, objectFile.getByteOrder());
final ProgbitsSectionImpl roDataImpl = new BasicProgbitsSectionImpl(roDataBuffer.getBackingArray());
roDataSection = objectFile.newProgbitsSection(SectionName.RODATA.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), writable, false, roDataImpl);
// Read-write data section
final RelocatableBuffer rwDataBuffer = new RelocatableBuffer(rwSectionSize, objectFile.getByteOrder());
final ProgbitsSectionImpl rwDataImpl = new BasicProgbitsSectionImpl(rwDataBuffer.getBackingArray());
rwDataSection = objectFile.newProgbitsSection(SectionName.DATA.getFormatDependentName(objectFile.getFormat()), objectFile.getPageSize(), true, false, rwDataImpl);
// Define symbols for the sections.
objectFile.createDefinedSymbol(textSection.getName(), textSection, 0, 0, false, false);
objectFile.createDefinedSymbol("__svm_text_end", textSection, textSectionSize, 0, false, SubstrateOptions.InternalSymbolsAreGlobal.getValue());
objectFile.createDefinedSymbol(roDataSection.getName(), roDataSection, 0, 0, false, false);
objectFile.createDefinedSymbol(rwDataSection.getName(), rwDataSection, 0, 0, false, false);
NativeImageHeapWriter writer = new NativeImageHeapWriter(heap, heapLayout);
// Write the section contents and record relocations.
// - The code goes in the text section, by itself.
textImpl.writeTextSection(debug, textSection, entryPoints);
// - The constants go at the beginning of the read-only data section.
codeCache.writeConstants(writer, roDataBuffer);
// - Non-heap global data goes at the beginning of the read-write data section.
cGlobals.writeData(rwDataBuffer, (offset, symbolName, isGlobalSymbol) -> objectFile.createDefinedSymbol(symbolName, rwDataSection, offset + RWDATA_CGLOBALS_PARTITION_OFFSET, wordSize, false, isGlobalSymbol || SubstrateOptions.InternalSymbolsAreGlobal.getValue()), (offset, symbolName, isGlobalSymbol) -> defineRelocationForSymbol(symbolName, offset));
defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET);
/*
* If we constructed debug info give the object file a chance to install it
*/
if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) {
Timer timer = TimerCollection.singleton().get(TimerCollection.Registry.DEBUG_INFO);
try (Timer.StopTimer t = timer.start()) {
ImageSingletons.add(SourceManager.class, new SourceManager());
DebugInfoProvider provider = new NativeImageDebugInfoProvider(debug, codeCache, heap);
objectFile.installDebugInfo(provider);
}
ProgressReporter.singleton().setDebugInfoTimer(timer);
}
// - Write the heap to its own section.
// Dynamic linkers/loaders generally don't ensure any alignment to more than page
// boundaries, so we take care of this ourselves in CommittedMemoryProvider, if we can.
int alignment = objectFile.getPageSize();
RelocatableBuffer heapSectionBuffer = new RelocatableBuffer(imageHeapSize, objectFile.getByteOrder());
ProgbitsSectionImpl heapSectionImpl = new BasicProgbitsSectionImpl(heapSectionBuffer.getBackingArray());
heapSection = objectFile.newProgbitsSection(SectionName.SVM_HEAP.getFormatDependentName(objectFile.getFormat()), alignment, writable, false, heapSectionImpl);
objectFile.createDefinedSymbol(heapSection.getName(), heapSection, 0, 0, false, false);
long offsetOfARelocatablePointer = writer.writeHeap(debug, heapSectionBuffer);
assert !SubstrateOptions.SpawnIsolates.getValue() || heapSectionBuffer.getByteBuffer().getLong((int) offsetOfARelocatablePointer) == 0L;
defineDataSymbol(Isolates.IMAGE_HEAP_BEGIN_SYMBOL_NAME, heapSection, 0);
defineDataSymbol(Isolates.IMAGE_HEAP_END_SYMBOL_NAME, heapSection, imageHeapSize);
defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset());
defineDataSymbol(Isolates.IMAGE_HEAP_RELOCATABLE_END_SYMBOL_NAME, heapSection, heapLayout.getReadOnlyRelocatableOffset() + heapLayout.getReadOnlyRelocatableSize());
defineDataSymbol(Isolates.IMAGE_HEAP_A_RELOCATABLE_POINTER_SYMBOL_NAME, heapSection, offsetOfARelocatablePointer);
defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_BEGIN_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset());
defineDataSymbol(Isolates.IMAGE_HEAP_WRITABLE_END_SYMBOL_NAME, heapSection, heapLayout.getWritableOffset() + heapLayout.getWritableSize());
// Mark the sections with the relocations from the maps.
markRelocationSitesFromBuffer(textBuffer, textImpl);
markRelocationSitesFromBuffer(roDataBuffer, roDataImpl);
markRelocationSitesFromBuffer(rwDataBuffer, rwDataImpl);
markRelocationSitesFromBuffer(heapSectionBuffer, heapSectionImpl);
// We print the heap statistics after the heap was successfully written because this
// could modify objects that will be part of the image heap.
printHeapStatistics(heap.getLayouter().getPartitions());
}
// [Footnote 1]
//
// Subject: Re: Do you know why text references can only be to constants?
// Date: Fri, 09 Jan 2015 12:51:15 -0800
// From: Christian Wimmer <christian.wimmer@oracle.com>
// To: Peter B. Kessler <Peter.B.Kessler@Oracle.COM>
//
// Code (i.e. the text section) needs to load the address of objects. So
// the read-only section contains a 8-byte slot with the address of the
// object that you actually want to load. A RIP-relative move instruction
// is used to load this 8-byte slot. The relocation for the move ensures
// the offset of the move is patched. And then a relocation from the
// read-only section to the actual native image heap ensures the 8-byte slot
// contains the actual address of the object to be loaded.
//
// Therefore, relocations in .text go only to things in .rodata; and
// relocations in .rodata go to .data in the current implementation
//
// It might be possible to have a RIP-relative load-effective-address (LEA)
// instruction to go directly from .text to .data, eliminating the memory
// access to load the address of an object. So I agree that allowing
// relocation from .text only to .rodata is an arbitrary restriction that
// could prevent future optimizations.
//
// -Christian
}
Aggregations