diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -856,10 +856,21 @@ } template static void readCallGraphsFromObjectFiles() { + const uint32_t sizeOfEntry = sizeof(Elf_CGProfile_Impl); for (auto file : objectFiles) { auto *obj = cast>(file); + std::vector> cgProfileC(obj->cgProfile.vec()); + for (uint32_t i = 0, size = obj->cgProfileRela.size(); i < size; i += 2) { + const Elf_Rel_Impl &relFrom = obj->cgProfileRela[i]; + const Elf_Rel_Impl &relTo = obj->cgProfileRela[i + 1]; + uint32_t symIndexFrom = relFrom.getSymbol(config->isMips64EL); + uint32_t symIndexTo = relTo.getSymbol(config->isMips64EL); + uint32_t index = relFrom.r_offset / sizeOfEntry; + cgProfileC[index].cgp_from = symIndexFrom; + cgProfileC[index].cgp_to = symIndexTo; + } - for (const Elf_CGProfile_Impl &cgpe : obj->cgProfile) { + for (const Elf_CGProfile_Impl &cgpe : cgProfileC) { auto *fromSym = dyn_cast(&obj->getSymbol(cgpe.cgp_from)); auto *toSym = dyn_cast(&obj->getSymbol(cgpe.cgp_to)); if (!fromSym || !toSym) diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -249,8 +249,10 @@ // Pointer to this input file's .llvm_addrsig section, if it has one. const Elf_Shdr *addrsigSec = nullptr; - // SHT_LLVM_CALL_GRAPH_PROFILE table + // SHT_LLVM_CALL_GRAPH_PROFILE table. ArrayRef cgProfile; + // SHT_LLVM_CALL_GRAPH_PROFILE relocations. + ArrayRef cgProfileRela; // Get cached DWARF information. DWARFCache *getDwarf(); diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -571,15 +571,19 @@ CHECK(obj.getSectionStringTable(objSections), this); std::vector> selectedGroups; + // SHT_LLVM_CALL_GRAPH_PROFILE Section Index. + size_t cgProfileSectionIndex = 0; for (size_t i = 0, e = objSections.size(); i < e; ++i) { if (this->sections[i] == &InputSection::discarded) continue; const Elf_Shdr &sec = objSections[i]; - if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) + if (sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE) { cgProfile = check(obj.template getSectionContentsAsArray(sec)); + cgProfileSectionIndex = i; + } // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. @@ -665,8 +669,12 @@ continue; const Elf_Shdr &sec = objSections[i]; - if (sec.sh_type == SHT_REL || sec.sh_type == SHT_RELA) + if (sec.sh_type == SHT_REL || sec.sh_type == SHT_RELA) { + if (sec.sh_info == cgProfileSectionIndex) { + cgProfileRela = CHECK(getObj().relas(sec), this); + } this->sections[i] = createInputSection(sec); + } // A SHF_LINK_ORDER section with sh_link=0 is handled as if it did not have // the flag. diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -1127,14 +1127,6 @@ OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section); } - MCSectionELF *CGProfileSection = nullptr; - if (!Asm.CGProfile.empty()) { - CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile", - ELF::SHT_LLVM_CALL_GRAPH_PROFILE, - ELF::SHF_EXCLUDE, 16); - SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection); - } - for (MCSectionELF *Group : Groups) { // Remember the offset into the file for this section. const uint64_t SecStart = align(Group->getAlignment()); @@ -1186,17 +1178,6 @@ } } - if (CGProfileSection) { - uint64_t SecStart = W.OS.tell(); - for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) { - W.write(CGPE.From->getSymbol().getIndex()); - W.write(CGPE.To->getSymbol().getIndex()); - W.write(CGPE.Count); - } - uint64_t SecEnd = W.OS.tell(); - SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd); - } - { uint64_t SecStart = W.OS.tell(); StrTabBuilder.write(W.OS); @@ -1471,7 +1452,11 @@ return; unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); - bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); + const auto Parent = cast(Fragment->getParent()); + // Emiting relocation with sybmol for CG Profile to help with --cg-profile. + bool RelocateWithSymbol = + shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type) || + (Parent->getType() == ELF::SHT_LLVM_CALL_GRAPH_PROFILE); uint64_t Addend = 0; FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined() diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -490,20 +490,26 @@ S->setUsedInReloc(); SRE = MCSymbolRefExpr::create(S, SRE->getKind(), getContext(), SRE->getLoc()); - return; } - // Not a temporary, referece it as a weak undefined. - bool Created; - getAssembler().registerSymbol(*S, &Created); - if (Created) - cast(S)->setBinding(ELF::STB_WEAK); + MCObjectStreamer::emitSymbolValue(S, 4); } void MCELFStreamer::finalizeCGProfile() { - for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) { + MCAssembler &Asm = getAssembler(); + if (Asm.CGProfile.empty()) + return; + MCSection *CGProfile = getAssembler().getContext().getELFSection( + ".llvm.call-graph-profile", ELF::SHT_LLVM_CALL_GRAPH_PROFILE, + ELF::SHF_EXCLUDE, 16 /* sizeof(Elf_CGProfile_Impl<>)*/); + PushSection(); + SwitchSection(CGProfile); + + for (MCAssembler::CGProfileEntry &E : Asm.CGProfile) { finalizeCGProfileEntry(E.From); finalizeCGProfileEntry(E.To); + emitIntValue(E.Count, sizeof(uint64_t)); } + PopSection(); } void MCELFStreamer::emitInstToFragment(const MCInst &Inst, diff --git a/llvm/test/MC/ELF/cgprofile.s b/llvm/test/MC/ELF/cgprofile.s --- a/llvm/test/MC/ELF/cgprofile.s +++ b/llvm/test/MC/ELF/cgprofile.s @@ -22,15 +22,15 @@ # CHECK-NEXT: Address: # CHECK-NEXT: Offset: # CHECK-NEXT: Size: 64 -# CHECK-NEXT: Link: 6 +# CHECK-NEXT: Link: 7 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 16 # CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 02000000 05000000 20000000 00000000 -# CHECK-NEXT: 0010: 07000000 02000000 0B000000 00000000 -# CHECK-NEXT: 0020: 06000000 03000000 14000000 00000000 -# CHECK-NEXT: 0030: 01000000 05000000 2A000000 00000000 +# CHECK-NEXT: 0000: 00000000 00000000 20000000 00000000 +# CHECK-NEXT: 0010: 00000000 00000000 0B000000 00000000 +# CHECK-NEXT: 0020: 00000000 00000000 14000000 00000000 +# CHECK-NEXT: 0030: 00000000 00000000 2A000000 00000000 # CHECK-NEXT: ) # CHECK: Symbols [ @@ -72,7 +72,7 @@ # CHECK: Name: freq # CHECK-NEXT: Value: # CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: # CHECK-NEXT: Other: # CHECK-NEXT: Section: Undefined diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -357,6 +357,7 @@ const Elf_Shdr *DotSymtabSec = nullptr; const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; + const Elf_Shdr *DotCGProfileSecRela = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; DenseMap> ShndxTables; Optional SONameOffset; @@ -1772,7 +1773,9 @@ return; typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); - for (const Elf_Shdr &Sec : Sections) { + uint32_t DotCGProfileSecIndex = 0; + for (unsigned i = 0, Size = Sections.size(); i < Size; ++i) { + const Elf_Shdr &Sec = Sections[i]; switch (Sec.sh_type) { case ELF::SHT_SYMTAB: if (!DotSymtabSec) @@ -1837,8 +1840,10 @@ SymbolVersionNeedSection = &Sec; break; case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: - if (!DotCGProfileSec) + if (!DotCGProfileSec) { DotCGProfileSec = &Sec; + DotCGProfileSecIndex = i; + } break; case ELF::SHT_LLVM_ADDRSIG: if (!DotAddrsigSec) @@ -1847,6 +1852,15 @@ } } + // Following LLD lead and doing a seperate loop in case relocation section + // comes before section it applies to. + for (const Elf_Shdr &Sec : Sections) { + if (Sec.sh_info == DotCGProfileSecIndex) { + DotCGProfileSecRela = &Sec; + break; + } + } + loadDynamicTable(); } @@ -6701,6 +6715,7 @@ if (!this->DotCGProfileSec) return; + std::vector CGProfileVec; Expected> CGProfileOrErr = this->Obj.template getSectionContentsAsArray( *this->DotCGProfileSec); @@ -6711,7 +6726,31 @@ return; } - for (const Elf_CGProfile &CGPE : *CGProfileOrErr) { + CGProfileVec = *CGProfileOrErr; + if (this->DotCGProfileSecRela) { + Expected CGProfileRelaOrError = + this->Obj.relas(*this->DotCGProfileSecRela); + if (!CGProfileRelaOrError) { + this->reportUniqueWarning( + "unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " + + toString(CGProfileOrErr.takeError()) + "with relocations."); + return; + } + + const uint32_t sizeOfEntry = sizeof(Elf_CGProfile_Impl); + for (uint32_t i = 0, size = CGProfileRelaOrError->size(); i < size; + i += 2) { + const Elf_Rel_Impl &relFrom = (*CGProfileRelaOrError)[i]; + const Elf_Rel_Impl &relTo = (*CGProfileRelaOrError)[i + 1]; + uint32_t symIndexFrom = relFrom.getSymbol(this->Obj.isMips64EL()); + uint32_t symIndexTo = relTo.getSymbol(this->Obj.isMips64EL()); + uint32_t index = relFrom.r_offset / sizeOfEntry; + CGProfileVec[index].cgp_from = symIndexFrom; + CGProfileVec[index].cgp_to = symIndexTo; + } + } + + for (const Elf_CGProfile &CGPE : CGProfileVec) { DictScope D(W, "CGProfileEntry"); W.printNumber("From", this->getStaticSymbolName(CGPE.cgp_from), CGPE.cgp_from);