// compute stub buffer size for the given section unsigned RuntimeDyldImpl::computeSectionStubBufSize(const ObjectFile &Obj, const SectionRef &Section) { unsigned StubSize = getMaxStubSize(); if (StubSize == 0) { return 0; } // FIXME: this is an inefficient way to handle this. We should computed the // necessary section allocation size in loadObject by walking all the sections // once. unsigned StubBufSize = 0; for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator RelSecI = SI->getRelocatedSection(); if (!(RelSecI == Section)) continue; for (const RelocationRef &Reloc : SI->relocations()) { (void)Reloc; StubBufSize += StubSize; } } // Get section data size and alignment uint64_t DataSize = Section.getSize(); uint64_t Alignment64 = Section.getAlignment(); // Add stubbuf size alignment unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; unsigned StubAlignment = getStubAlignment(); unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); if (StubAlignment > EndAlignment) StubBufSize += StubAlignment - EndAlignment; return StubBufSize; }
void ObjectLoadListener::recordRelocations( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator Section = SI->getRelocatedSection(); if (Section == SE) { continue; } StringRef SectionName; std::error_code ErrorCode = Section->getName(SectionName); if (ErrorCode) { assert(false && ErrorCode.message().c_str()); } if (SectionName.startswith(".debug") || SectionName.startswith(".rela.debug") || !SectionName.compare(".pdata") || SectionName.startswith(".eh_frame") || SectionName.startswith(".rela.eh_frame")) { // Skip sections whose contents are not directly reported to the EE continue; } relocation_iterator I = SI->relocation_begin(); relocation_iterator E = SI->relocation_end(); for (; I != E; ++I) { symbol_iterator Symbol = I->getSymbol(); assert(Symbol != Obj.symbol_end()); ErrorOr<section_iterator> SymbolSectionOrErr = Symbol->getSection(); assert(!SymbolSectionOrErr.getError()); object::section_iterator SymbolSection = *SymbolSectionOrErr; const bool IsExtern = SymbolSection == Obj.section_end(); uint64_t RelType = I->getType(); uint64_t Offset = I->getOffset(); uint8_t *RelocationTarget; if (IsExtern) { // This is an external symbol. Verify that it's one we created for // a global variable and report the relocation via Jit interface. ErrorOr<StringRef> NameOrError = Symbol->getName(); assert(NameOrError); StringRef TargetName = NameOrError.get(); auto MapIter = Context->NameToHandleMap.find(TargetName); if (MapIter == Context->NameToHandleMap.end()) { // The xdata gets a pointer to our personality routine, which we // dummied up. We can safely skip it since the EE isn't actually // going to use the value (it inserts the correct one before handing // the xdata off to the OS). assert(!TargetName.compare("ProcessCLRException")); assert(SectionName.startswith(".xdata")); continue; } else { assert(MapIter->second == Context->NameToHandleMap[TargetName]); RelocationTarget = (uint8_t *)MapIter->second; } } else { RelocationTarget = (uint8_t *)(L.getSectionLoadAddress(*SymbolSection) + Symbol->getValue()); } uint64_t Addend = 0; uint64_t EERelType = getRelocationType(RelType); uint64_t SectionAddress = L.getSectionLoadAddress(*Section); assert(SectionAddress != 0); uint8_t *FixupAddress = (uint8_t *)(SectionAddress + Offset); if (Obj.isELF()) { // Addend is part of the relocation ELFRelocationRef ElfReloc(*I); ErrorOr<uint64_t> ElfAddend = ElfReloc.getAddend(); assert(!ElfAddend.getError()); Addend = ElfAddend.get(); } else { // Addend is read from the location to be fixed up Addend = getRelocationAddend(RelType, FixupAddress); } Context->JitInfo->recordRelocation(FixupAddress, RelocationTarget + Addend, EERelType); } } }
// Compute an upper bound of the memory size that is required to load all // sections void RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize, uint64_t &DataSizeRO, uint64_t &DataSizeRW) { // Compute the size of all sections required for execution std::vector<uint64_t> CodeSectionSizes; std::vector<uint64_t> ROSectionSizes; std::vector<uint64_t> RWSectionSizes; uint64_t MaxAlignment = sizeof(void *); // Collect sizes of all sections to be loaded; // also determine the max alignment of all sections for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { const SectionRef &Section = *SI; bool IsRequired = Section.isRequiredForExecution(); // Consider only the sections that are required to be loaded for execution if (IsRequired) { StringRef Name; uint64_t DataSize = Section.getSize(); uint64_t Alignment64 = Section.getAlignment(); bool IsCode = Section.isText(); bool IsReadOnly = Section.isReadOnlyData(); Check(Section.getName(Name)); unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; uint64_t StubBufSize = computeSectionStubBufSize(Obj, Section); uint64_t SectionSize = DataSize + StubBufSize; // The .eh_frame section (at least on Linux) needs an extra four bytes // padded // with zeroes added at the end. For MachO objects, this section has a // slightly different name, so this won't have any effect for MachO // objects. if (Name == ".eh_frame") SectionSize += 4; if (SectionSize > 0) { // save the total size of the section if (IsCode) { CodeSectionSizes.push_back(SectionSize); } else if (IsReadOnly) { ROSectionSizes.push_back(SectionSize); } else { RWSectionSizes.push_back(SectionSize); } // update the max alignment if (Alignment > MaxAlignment) { MaxAlignment = Alignment; } } } } // Compute the size of all common symbols uint64_t CommonSize = 0; for (symbol_iterator I = Obj.symbol_begin(), E = Obj.symbol_end(); I != E; ++I) { uint32_t Flags = I->getFlags(); if (Flags & SymbolRef::SF_Common) { // Add the common symbols to a list. We'll allocate them all below. uint64_t Size = 0; Check(I->getSize(Size)); CommonSize += Size; } } if (CommonSize != 0) { RWSectionSizes.push_back(CommonSize); } // Compute the required allocation space for each different type of sections // (code, read-only data, read-write data) assuming that all sections are // allocated with the max alignment. Note that we cannot compute with the // individual alignments of the sections, because then the required size // depends on the order, in which the sections are allocated. CodeSize = computeAllocationSizeForSections(CodeSectionSizes, MaxAlignment); DataSizeRO = computeAllocationSizeForSections(ROSectionSizes, MaxAlignment); DataSizeRW = computeAllocationSizeForSections(RWSectionSizes, MaxAlignment); }
void ObjectLoadListener::recordRelocations( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); SI != SE; ++SI) { section_iterator Section = SI->getRelocatedSection(); if (Section == SE) { continue; } StringRef SectionName; std::error_code ErrorCode = Section->getName(SectionName); if (ErrorCode) { assert(false && ErrorCode.message().c_str()); } if (SectionName.startswith(".debug") || SectionName.startswith(".rela.debug") || !SectionName.compare(".pdata") || SectionName.startswith(".eh_frame") || SectionName.startswith(".rela.eh_frame")) { // Skip sections whose contents are not directly reported to the EE continue; } relocation_iterator I = SI->relocation_begin(); relocation_iterator E = SI->relocation_end(); for (; I != E; ++I) { symbol_iterator Symbol = I->getSymbol(); assert(Symbol != Obj.symbol_end()); ErrorOr<section_iterator> SymbolSectionOrErr = Symbol->getSection(); assert(!SymbolSectionOrErr.getError()); object::section_iterator SymbolSection = *SymbolSectionOrErr; const bool IsExtern = SymbolSection == Obj.section_end(); uint64_t RelType = I->getType(); uint64_t Offset = I->getOffset(); uint8_t *RelocationTarget = nullptr; if (IsExtern) { // This is an external symbol. Verify that it's one we created for // a global variable and report the relocation via Jit interface. ErrorOr<StringRef> NameOrError = Symbol->getName(); assert(NameOrError); StringRef TargetName = NameOrError.get(); assert(Context->NameToHandleMap.count(TargetName) == 1); RelocationTarget = (uint8_t *)Context->NameToHandleMap[TargetName]; } else { RelocationTarget = (uint8_t *)(L.getSectionLoadAddress(*SymbolSection) + Symbol->getValue()); } uint64_t Addend = 0; uint64_t EERelType = getRelocationType(RelType); uint64_t SectionAddress = L.getSectionLoadAddress(*Section); assert(SectionAddress != 0); uint8_t *FixupAddress = (uint8_t *)(SectionAddress + Offset); if (Obj.isELF()) { // Addend is part of the relocation ELFRelocationRef ElfReloc(*I); ErrorOr<uint64_t> ElfAddend = ElfReloc.getAddend(); assert(!ElfAddend.getError()); Addend = ElfAddend.get(); } else { // Addend is read from the location to be fixed up Addend = getRelocationAddend(RelType, FixupAddress); } Context->JitInfo->recordRelocation(FixupAddress, RelocationTarget + Addend, EERelType); } } }