diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -167,6 +167,10 @@ /// List of relocations associated with data in the constant island std::map Relocations; + /// Set true if constant island contains dynamic relocations, which may + /// happen if binary is linked with -z notext option. + bool HasDynamicRelocations{false}; + /// Offsets in function that are data values in a constant island identified /// after disassembling std::map Offsets; @@ -1945,6 +1949,28 @@ return Symbol; } + /// Support dynamic relocations in constant islands, which may happen if + /// binary is linked with -z notext option. + void markIslandDynamicRelocationAtAddress(uint64_t Address) { + if (!isInConstantIsland(Address)) { + errs() << "BOLT-ERROR: dynamic relocation found for text section at 0x" + << Twine::utohexstr(Address) << "\n"; + exit(1); + } + + // Mark island to have dynamic relocation + Islands->HasDynamicRelocations = true; + + // Create island access, so we would emit the label and + // move binary data during updateOutputValues, making us emit + // dynamic relocation with the right offset value. + getOrCreateIslandAccess(Address); + } + + bool hasDynamicRelocationAtIsland() const { + return !!(Islands && Islands->HasDynamicRelocations); + } + /// Called by an external function which wishes to emit references to constant /// island symbols of this function. We create a proxy for it, so we emit /// separate symbols when emitting our constant island on behalf of this other diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -547,18 +547,6 @@ ErrorOr LSDASection{std::errc::bad_address}; ErrorOr EHFrameSection{std::errc::bad_address}; - /// .got.plt sections. - /// - /// Contains jump slots (addresses) indirectly referenced by - /// instructions in .plt section. - ErrorOr GOTPLTSection{std::errc::bad_address}; - - /// .rela.plt section. - /// - /// Contains relocations against .got.plt. - ErrorOr RelaPLTSection{std::errc::bad_address}; - ErrorOr RelaDynSection{std::errc::bad_address}; - /// .note.gnu.build-id section. ErrorOr BuildIDSection{std::errc::bad_address}; diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -391,8 +391,18 @@ --IslandIter; if (IslandIter != AddressToConstantIslandMap.end()) { - if (MCSymbol *IslandSym = - IslandIter->second->getOrCreateProxyIslandAccess(Address, BF)) { + // Fall-back to referencing the original constant island in the presence + // of dynamic relocs, as we currently do not support cloning them. + // Notice: we might fail to link because of this, if the original constant + // island we are referring would be emitted too far away. + if (IslandIter->second->hasDynamicRelocationAtIsland()) { + MCSymbol *IslandSym = + IslandIter->second->getOrCreateIslandAccess(Address); + if (IslandSym) + return std::make_pair(IslandSym, 0); + } else if (MCSymbol *IslandSym = + IslandIter->second->getOrCreateProxyIslandAccess(Address, + BF)) { BF.createIslandDependency(IslandSym, IslandIter->second); return std::make_pair(IslandSym, 0); } diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -4088,6 +4088,16 @@ const uint64_t DataOffset = Layout.getSymbolOffset(*getFunctionConstantIslandLabel()); setOutputDataAddress(BaseAddress + DataOffset); + for (auto It : Islands->Offsets) { + const uint64_t OldOffset = It.first; + BinaryData *BD = BC.getBinaryDataAtAddress(getAddress() + OldOffset); + if (!BD) + continue; + + MCSymbol *Symbol = It.second; + const uint64_t NewOffset = Layout.getSymbolOffset(*Symbol); + BD->setOutputLocation(*getCodeSection(), NewOffset); + } } if (isSplit()) { for (FunctionFragment &FF : getLayout().getSplitFragments()) { diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -1278,6 +1278,25 @@ llvm_unreachable("Unknown marker"); } + if (BC->isAArch64()) { + // Check for dynamic relocations that might be contained in + // constant islands. + for (const BinarySection &Section : BC->allocatableSections()) { + const uint64_t SectionAddress = Section.getAddress(); + for (const Relocation &Rel : Section.dynamicRelocations()) { + const uint64_t RelAddress = SectionAddress + Rel.Offset; + BinaryFunction *BF = + BC->getBinaryFunctionContainingAddress(RelAddress, + /*CheckPastEnd*/ false, + /*UseMaxSize*/ true); + if (BF) { + assert(Rel.isRelative() && "Expected relative relocation for island"); + BF->markIslandDynamicRelocationAtAddress(RelAddress); + } + } + } + } + if (opts::LinuxKernelMode) { // Read all special linux kernel sections and their relocations processLKSections(); @@ -1679,9 +1698,6 @@ HasSymbolTable = (bool)BC->getUniqueSectionByName(".symtab"); LSDASection = BC->getUniqueSectionByName(".gcc_except_table"); EHFrameSection = BC->getUniqueSectionByName(".eh_frame"); - GOTPLTSection = BC->getUniqueSectionByName(".got.plt"); - RelaPLTSection = BC->getUniqueSectionByName(".rela.plt"); - RelaDynSection = BC->getUniqueSectionByName(".rela.dyn"); BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id"); SDTSection = BC->getUniqueSectionByName(".note.stapsdt"); PseudoProbeDescSection = BC->getUniqueSectionByName(".pseudo_probe_desc"); @@ -3177,6 +3193,12 @@ for (auto &BFI : BC->getBinaryFunctions()) { BinaryFunction &Function = BFI.second; + // Set function as non-simple if it has dynamic relocations + // in constant island, we don't want this function to be optimized + // e.g. function splitting is unsupported. + if (Function.hasDynamicRelocationAtIsland()) + Function.setSimple(false); + if (Function.empty()) continue; @@ -5133,6 +5155,7 @@ auto setSectionFileOffsets = [&](uint64_t Address, uint64_t &Start, uint64_t &End) { ErrorOr Section = BC->getSectionForAddress(Address); + assert(Section && "cannot get relocation section"); Start = Section->getInputFileOffset(); End = Start + Section->getSize(); }; @@ -5157,6 +5180,11 @@ auto writeRelocations = [&](bool PatchRelative) { for (BinarySection &Section : BC->allocatableSections()) { + const uint64_t SectionInputAddress = Section.getAddress(); + uint64_t SectionAddress = Section.getOutputAddress(); + if (!SectionAddress) + SectionAddress = SectionInputAddress; + for (const Relocation &Rel : Section.dynamicRelocations()) { const bool IsRelative = Rel.isRelative(); if (PatchRelative != IsRelative) @@ -5166,13 +5194,13 @@ ++DynamicRelativeRelocationsCount; Elf_Rela NewRelA; - uint64_t SectionAddress = Section.getOutputAddress(); - SectionAddress = - SectionAddress == 0 ? Section.getAddress() : SectionAddress; MCSymbol *Symbol = Rel.Symbol; uint32_t SymbolIdx = 0; uint64_t Addend = Rel.Addend; + uint64_t RelOffset = + getNewFunctionOrDataAddress(SectionInputAddress + Rel.Offset); + RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset; if (Rel.Symbol) { SymbolIdx = getOutputDynamicSymbolIndex(Symbol); } else { @@ -5183,7 +5211,7 @@ } NewRelA.setSymbolAndType(SymbolIdx, Rel.Type, EF.isMips64EL()); - NewRelA.r_offset = SectionAddress + Rel.Offset; + NewRelA.r_offset = RelOffset; NewRelA.r_addend = Addend; const bool IsJmpRel = diff --git a/bolt/test/AArch64/constant_island_pie_update.s b/bolt/test/AArch64/constant_island_pie_update.s --- a/bolt/test/AArch64/constant_island_pie_update.s +++ b/bolt/test/AArch64/constant_island_pie_update.s @@ -1,18 +1,29 @@ // This test checks that the constant island value is updated if it // has dynamic relocation. +// Also check that we don't duplicate CI if it has dynamic relocations. -# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \ -# RUN: %s -o %t.o -# RUN: %clang %cflags -fPIC -pie %t.o -o %t.exe -Wl,-q -nostdlib -Wl,-z,notext -# RUN: llvm-bolt %t.exe -o %t.bolt --use-old-text=0 --lite=0 -# RUN: llvm-objdump -j .text -dR %t.bolt | FileCheck %s +# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags -fPIC -pie %t.o -o %t.rela.exe -nostdlib \ +# RUN: -Wl,-q -Wl,-z,notext +# RUN: llvm-bolt %t.rela.exe -o %t.rela.bolt --use-old-text=0 --lite=0 +# RUN: llvm-objdump -j .text -d %t.rela.bolt | FileCheck %s +# RUN: llvm-readelf -rsW %t.rela.bolt | FileCheck --check-prefix=ELFCHECK %s -# CHECK: R_AARCH64_RELATIVE *ABS*+0x[[#%x,ADDR:]] -# CHECK: [[#ADDR]] : +// Check that the CI value was updated +# CHECK: [[#%x,ADDR:]] : # CHECK: {{.*}} <$d>: # CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]] # CHECK-NEXT: {{.*}} .word 0x00000000 +// Check that we've relaxed adr to adrp + add to refer external CI +# CHECK: : +# CHECK-NEXT: adrp +# CHECK-NEXT: add + +// Check that relocation offset was updated +# ELFCHECK: [[#%x,OFF:]] [[#%x,INFO_DYN:]] R_AARCH64_RELATIVE +# ELFCHECK: {{.*}}[[#OFF]] {{.*}} $d + .text .align 4 .local exitLocal @@ -20,6 +31,8 @@ exitLocal: add x1, x1, #1 add x1, x1, #1 + nop + nop ret .size exitLocal, .-exitLocal @@ -36,3 +49,10 @@ .Lci: .xword exitLocal .size _start, .-_start + + .global addressDynCi + .type addressDynCi, %function +addressDynCi: + adr x1, .Lci + bl _start +.size addressDynCi, .-addressDynCi