Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp =================================================================== --- lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -703,7 +703,7 @@ unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; unsigned PaddingSize = 0; unsigned StubBufSize = 0; - bool IsRequired = isRequiredForExecution(Section) || ProcessAllSections; + bool IsRequired = isRequiredForExecution(Section); bool IsVirtual = Section.isVirtual(); bool IsZeroInit = isZeroInit(Section); bool IsReadOnly = isReadOnlyData(Section); @@ -743,8 +743,8 @@ Alignment = std::max(Alignment, getStubAlignment()); // Some sections, such as debug info, don't need to be loaded for execution. - // Leave those where they are. - if (IsRequired) { + // Process those only if explicitly requested. + if (IsRequired || ProcessAllSections) { Allocate = DataSize + PaddingSize + StubBufSize; if (!Allocate) Allocate = 1; @@ -788,6 +788,10 @@ Sections.push_back( SectionEntry(Name, Addr, DataSize, Allocate, (uintptr_t)pData)); + // Debug info sections are linked as if their load address was zero + if (!IsRequired) + Sections.back().setLoadAddress(0); + if (Checker) Checker->registerSection(Obj.getFileName(), SectionID); Index: unittests/ExecutionEngine/MCJIT/MCJITTest.cpp =================================================================== --- unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -12,9 +12,20 @@ // //===----------------------------------------------------------------------===// +#include "MCJITTestBase.h" #include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/DynamicLibrary.h" -#include "MCJITTestBase.h" +#include "llvm/Support/TargetRegistry.h" #include "gtest/gtest.h" using namespace llvm; @@ -281,4 +292,142 @@ EXPECT_FALSE(std::find(I, E, "Foo2") == E); } +static Function *insertMainWithDI(LLVMContext &Context, Module &M) { + DIBuilder DIB(M); + DIFile *File = DIB.createFile("-", "."); + DIB.createCompileUnit(dwarf::DW_LANG_C99, File, "producer", false, "", 0); + DISubroutineType *MainType = DIB.createSubroutineType({}); + DISubprogram *DIMain = DIB.createFunction(File, "main", "main", File, 1, + MainType, false, true, 1); + DILocation *Loc = DILocation::get(Context, 1, 1, DIMain, nullptr); + Function *Main = Function::Create(TypeBuilder::get(Context), + GlobalValue::ExternalLinkage, "main", &M); + Main->setSubprogram(DIMain); + BasicBlock *Entry = BasicBlock::Create(Context, "entry", Main); + ReturnInst *Ret = + IRBuilder<>(Entry).CreateRet(ConstantInt::get(Context, APInt(32, 47))); + Ret->setDebugLoc(Loc); + DIB.finalize(); + + return Main; +} + +TEST_F(MCJITTest, ProcessAllSections) { + Function *Main = insertMainWithDI(Context, *M); + + createJIT(std::move(M)); + TheJIT->setProcessAllSections(true); + TheJIT->finalizeObject(); + + uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str()); + ASSERT_NE(0u, ptr) << "Unable to get pointer to main() from JIT"; + + int (*FuncPtr)() = (int (*)())ptr; + int returnCode = FuncPtr(); + EXPECT_EQ(returnCode, 47); +} + +static void createObject(SmallVectorImpl &Object) { + LLVMInitializeX86TargetInfo(); + LLVMInitializeX86TargetMC(); + LLVMInitializeX86Target(); + LLVMInitializeX86AsmPrinter(); + + std::string ErrorStr; + Triple TheTriple("x86_64-pc-linux"); + const Target *TheTarget = + TargetRegistry::lookupTarget("", TheTriple, ErrorStr); + ASSERT_NE(nullptr, TheTarget) << ErrorStr; + + std::unique_ptr MRI( + TheTarget->createMCRegInfo(TheTriple.getTriple())); + ASSERT_NE(nullptr, MRI); + + std::unique_ptr MAB(TheTarget->createMCAsmBackend( + *MRI, TheTriple.getTriple(), "", MCTargetOptions())); + ASSERT_NE(nullptr, MAB); + + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*MRI, TheTriple.getTriple())); + ASSERT_NE(nullptr, MAI); + + auto MOFI = llvm::make_unique(); + + std::unique_ptr MII(TheTarget->createMCInstrInfo()); + ASSERT_NE(nullptr, MII); + + MCContext MC(MAI.get(), MRI.get(), MOFI.get()); + MOFI->InitMCObjectFileInfo(TheTriple, false, CodeModel::Default, MC); + + std::unique_ptr MCE( + TheTarget->createMCCodeEmitter(*MII, *MRI, MC)); + ASSERT_NE(nullptr, MCE); + + std::unique_ptr MSTI( + TheTarget->createMCSubtargetInfo(TheTriple.getTriple(), "", "")); + + raw_svector_ostream Stream(Object); + + std::unique_ptr Streamer(TheTarget->createMCObjectStreamer( + TheTriple, MC, *MAB.release(), Stream, MCE.release(), *MSTI, false, false, + false)); + + Streamer->SwitchSection(MOFI->getDwarfFrameSection()); + MCSymbol *SectionEnd = MC.createTempSymbol(); + Streamer->EmitSymbolValue(SectionEnd, 4); + Streamer->EmitSymbolValue(SectionEnd, 4); + Streamer->EmitLabel(SectionEnd); + Streamer->Finish(); +} + +class DebugFrameFetcher : public SectionMemoryManager { +public: + DebugFrameFetcher(ArrayRef &DebugFrame) : DebugFrame(DebugFrame) {} + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool isReadOnly) override { + uint8_t *Ptr = SectionMemoryManager::allocateDataSection( + Size, Alignment, SectionID, SectionName, isReadOnly); + if (SectionName == ".debug_frame") + DebugFrame = ArrayRef(Ptr, Size); + return Ptr; + } + +private: + ArrayRef &DebugFrame; +}; + +TEST_F(MCJITTest, debug_info_relocation) { + // Test that debug info sections are relocated as if their load address was + // zero + + SmallString<0> Object; + createObject(Object); + + ArrayRef DebugFrame; + EngineBuilder EB(std::move(M)); + TheJIT.reset(EB.setEngineKind(EngineKind::JIT) + .setMCJITMemoryManager( + llvm::make_unique(DebugFrame)) + .setOptLevel(CodeGenOpt::None) + .setCodeModel(CodeModel::JITDefault) + .setMArch("") + .setMCPU(sys::getHostCPUName()) + .create(EB.selectTarget(Triple("x86_64-pc-linux"), "", "", + SmallVector()))); + ASSERT_NE(nullptr, TheJIT); + auto ObjectOrError = + object::ObjectFile::createObjectFile(MemoryBufferRef(Object, "test.o")); + ASSERT_TRUE(bool(ObjectOrError)); + TheJIT->setProcessAllSections(true); + TheJIT->addObjectFile(std::move(*ObjectOrError)); + TheJIT->finalizeObject(); + + // The real section may have padding, so we only test size()>=8 + ASSERT_GE(DebugFrame.size(), 8u); + uint8_t Contents[] = {8, 0, 0, 0, 8, 0, 0, 0}; + ASSERT_EQ(makeArrayRef(Contents), DebugFrame.take_front(8)); +} + } // end anonymous namespace