Index: clang/test/CodeGen/cfstring-elf-sections-x86_64.c =================================================================== --- clang/test/CodeGen/cfstring-elf-sections-x86_64.c +++ clang/test/CodeGen/cfstring-elf-sections-x86_64.c @@ -7,12 +7,13 @@ const CFStringRef two = (CFStringRef)__builtin___CFStringMakeConstantString("\xef\xbf\xbd\x74\xef\xbf\xbd\x77\xef\xbf\xbd\x6f"); // CHECK-ELF-DATA-SECTION: .type .L.str,@object -// CHECK-ELF-DATA-SECTION: .section .rodata,"a",@progbits +// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS",@progbits,1,unique,1 + // CHECK-ELF-DATA-SECTION: .L.str: // CHECK-ELF-DATA-SECTION: .asciz "one" // CHECK-ELF-DATA-SECTION: .type .L.str.1,@object -// CHECK-ELF-DATA-SECTION: .section .rodata,"a",@progbits +// CHECK-ELF-DATA-SECTION: .section .rodata,"aMS",@progbits,2,unique,2 // CHECK-ELF-DATA-SECTION: .L.str.1: // CHECK-ELF-DATA-SECTION: .short 65533 // CHECK-ELF-DATA-SECTION: .short 116 Index: llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -1,250 +1,277 @@ -//==- llvm/CodeGen/TargetLoweringObjectFileImpl.h - Object Info --*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements classes used to handle lowerings specific to common -// object file formats. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H -#define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H - -#include "llvm/BinaryFormat/XCOFF.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/Target/TargetLoweringObjectFile.h" - -namespace llvm { - -class GlobalValue; -class MachineModuleInfo; -class Mangler; -class MCContext; -class MCSection; -class MCSymbol; -class TargetMachine; - -class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { - bool UseInitArray = false; - mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections - -protected: - MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = - MCSymbolRefExpr::VK_None; - const TargetMachine *TM = nullptr; - -public: - TargetLoweringObjectFileELF() = default; - ~TargetLoweringObjectFileELF() override = default; - - void Initialize(MCContext &Ctx, const TargetMachine &TM) override; - - /// Emit Obj-C garbage collection and linker options. - void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - - void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL, - const MCSymbol *Sym) const override; - - /// Given a constant with the SectionKind, return a section that it should be - /// placed in. - MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - unsigned &Align) const override; - - MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *getSectionForJumpTable(const Function &F, - const TargetMachine &TM) const override; - - bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, - const Function &F) const override; - - /// Return an MCExpr to use for a reference to the specified type info global - /// variable from exception handling information. - const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, - unsigned Encoding, - const TargetMachine &TM, - MachineModuleInfo *MMI, - MCStreamer &Streamer) const override; - - // The symbol that gets passed to .cfi_personality. - MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, - const TargetMachine &TM, - MachineModuleInfo *MMI) const override; - - void InitializeELF(bool UseInitArray_); - MCSection *getStaticCtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - MCSection *getStaticDtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const override; - - MCSection *getSectionForCommandLines() const override; -}; - -class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { -public: - TargetLoweringObjectFileMachO(); - ~TargetLoweringObjectFileMachO() override = default; - - void Initialize(MCContext &Ctx, const TargetMachine &TM) override; - - /// Emit the module flags that specify the garbage collection information. - void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - - MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - unsigned &Align) const override; - - /// The mach-o version of this method defaults to returning a stub reference. - const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, - unsigned Encoding, - const TargetMachine &TM, - MachineModuleInfo *MMI, - MCStreamer &Streamer) const override; - - // The symbol that gets passed to .cfi_personality. - MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, - const TargetMachine &TM, - MachineModuleInfo *MMI) const override; - - /// Get MachO PC relative GOT entry relocation - const MCExpr *getIndirectSymViaGOTPCRel(const GlobalValue *GV, - const MCSymbol *Sym, - const MCValue &MV, int64_t Offset, - MachineModuleInfo *MMI, - MCStreamer &Streamer) const override; - - void getNameWithPrefix(SmallVectorImpl &OutName, const GlobalValue *GV, - const TargetMachine &TM) const override; -}; - -class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { - mutable unsigned NextUniqueID = 0; - -public: - ~TargetLoweringObjectFileCOFF() override = default; - - void Initialize(MCContext &Ctx, const TargetMachine &TM) override; - MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - void getNameWithPrefix(SmallVectorImpl &OutName, const GlobalValue *GV, - const TargetMachine &TM) const override; - - MCSection *getSectionForJumpTable(const Function &F, - const TargetMachine &TM) const override; - - /// Emit Obj-C garbage collection and linker options. - void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; - - MCSection *getStaticCtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - MCSection *getStaticDtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - - void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const override; - - void emitLinkerFlagsForUsed(raw_ostream &OS, - const GlobalValue *GV) const override; - - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const override; - - /// Given a mergeable constant with the specified size and relocation - /// information, return a section that it should be placed in. - MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - unsigned &Align) const override; -}; - -class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { - mutable unsigned NextUniqueID = 0; - -public: - TargetLoweringObjectFileWasm() = default; - ~TargetLoweringObjectFileWasm() override = default; - - MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, - const Function &F) const override; - - void InitializeWasm(); - MCSection *getStaticCtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - MCSection *getStaticDtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const override; -}; - -class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile { -public: - TargetLoweringObjectFileXCOFF() = default; - ~TargetLoweringObjectFileXCOFF() override = default; - - void Initialize(MCContext &Ctx, const TargetMachine &TM) override; - - bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, - const Function &F) const override; - - MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *getStaticCtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - MCSection *getStaticDtorSection(unsigned Priority, - const MCSymbol *KeySym) const override; - - const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const override; - - MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const override; - - MCSection *getSectionForJumpTable(const Function &F, - const TargetMachine &TM) const override; - - /// Given a constant with the SectionKind, return a section that it should be - /// placed in. - MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - unsigned &Align) const override; - - static XCOFF::StorageClass getStorageClassForGlobal(const GlobalObject *GO); -}; - -} // end namespace llvm - -#endif // LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H +//==- llvm/CodeGen/TargetLoweringObjectFileImpl.h - Object Info --*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements classes used to handle lowerings specific to common +// object file formats. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H +#define LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include + +namespace llvm { + +class GlobalValue; +class MachineModuleInfo; +class Mangler; +class MCContext; +class MCSection; +class MCSymbol; +class TargetMachine; + +class TargetLoweringObjectFileELF : public TargetLoweringObjectFile { + bool UseInitArray = false; + mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections + + // Mergeable globals must be assigned to a section with a compatible entry + // size. This map is used to assign unique IDs to mergeable sections to + // distinguish between sections with identical names but incompatible entry + // sizes. This is required if mergeable globals are explicitly assigned to a + // section, e.g. via _attribute_((section("myname"))). + struct ELFEntrySizeKey { + std::string SectionName; + unsigned Flags; + unsigned EntrySize; + + ELFEntrySizeKey(StringRef SectionName, unsigned Flags, unsigned EntrySize) + : SectionName(SectionName), Flags(Flags), EntrySize(EntrySize) {} + + bool operator<(const ELFEntrySizeKey &Other) const { + if (SectionName != Other.SectionName) + return SectionName < Other.SectionName; + if ((Flags & ELF::SHF_STRINGS) != (Other.Flags & ELF::SHF_STRINGS)) + return (Other.Flags & ELF::SHF_STRINGS); + return EntrySize < Other.EntrySize; + } + }; + + mutable std::map ELFEntrySizeMap; + +protected: + MCSymbolRefExpr::VariantKind PLTRelativeVariantKind = + MCSymbolRefExpr::VK_None; + const TargetMachine *TM = nullptr; + +public: + TargetLoweringObjectFileELF() = default; + ~TargetLoweringObjectFileELF() override = default; + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + /// Emit Obj-C garbage collection and linker options. + void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + + void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &DL, + const MCSymbol *Sym) const override; + + /// Given a constant with the SectionKind, return a section that it should be + /// placed in. + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *getSectionForJumpTable(const Function &F, + const TargetMachine &TM) const override; + + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, + const Function &F) const override; + + /// Return an MCExpr to use for a reference to the specified type info global + /// variable from exception handling information. + const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, + unsigned Encoding, + const TargetMachine &TM, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; + + // The symbol that gets passed to .cfi_personality. + MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, + const TargetMachine &TM, + MachineModuleInfo *MMI) const override; + + void InitializeELF(bool UseInitArray_); + MCSection *getStaticCtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + MCSection *getStaticDtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; + + MCSection *getSectionForCommandLines() const override; +}; + +class TargetLoweringObjectFileMachO : public TargetLoweringObjectFile { +public: + TargetLoweringObjectFileMachO(); + ~TargetLoweringObjectFileMachO() override = default; + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + /// Emit the module flags that specify the garbage collection information. + void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; + + /// The mach-o version of this method defaults to returning a stub reference. + const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, + unsigned Encoding, + const TargetMachine &TM, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; + + // The symbol that gets passed to .cfi_personality. + MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, + const TargetMachine &TM, + MachineModuleInfo *MMI) const override; + + /// Get MachO PC relative GOT entry relocation + const MCExpr *getIndirectSymViaGOTPCRel(const GlobalValue *GV, + const MCSymbol *Sym, + const MCValue &MV, int64_t Offset, + MachineModuleInfo *MMI, + MCStreamer &Streamer) const override; + + void getNameWithPrefix(SmallVectorImpl &OutName, const GlobalValue *GV, + const TargetMachine &TM) const override; +}; + +class TargetLoweringObjectFileCOFF : public TargetLoweringObjectFile { + mutable unsigned NextUniqueID = 0; + +public: + ~TargetLoweringObjectFileCOFF() override = default; + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + void getNameWithPrefix(SmallVectorImpl &OutName, const GlobalValue *GV, + const TargetMachine &TM) const override; + + MCSection *getSectionForJumpTable(const Function &F, + const TargetMachine &TM) const override; + + /// Emit Obj-C garbage collection and linker options. + void emitModuleMetadata(MCStreamer &Streamer, Module &M) const override; + + MCSection *getStaticCtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + MCSection *getStaticDtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + + void emitLinkerFlagsForGlobal(raw_ostream &OS, + const GlobalValue *GV) const override; + + void emitLinkerFlagsForUsed(raw_ostream &OS, + const GlobalValue *GV) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; + + /// Given a mergeable constant with the specified size and relocation + /// information, return a section that it should be placed in. + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; +}; + +class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile { + mutable unsigned NextUniqueID = 0; + +public: + TargetLoweringObjectFileWasm() = default; + ~TargetLoweringObjectFileWasm() override = default; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, + const Function &F) const override; + + void InitializeWasm(); + MCSection *getStaticCtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + MCSection *getStaticDtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; +}; + +class TargetLoweringObjectFileXCOFF : public TargetLoweringObjectFile { +public: + TargetLoweringObjectFileXCOFF() = default; + ~TargetLoweringObjectFileXCOFF() override = default; + + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + + bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, + const Function &F) const override; + + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *getStaticCtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + MCSection *getStaticDtorSection(unsigned Priority, + const MCSymbol *KeySym) const override; + + const MCExpr *lowerRelativeReference(const GlobalValue *LHS, + const GlobalValue *RHS, + const TargetMachine &TM) const override; + + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override; + + MCSection *getSectionForJumpTable(const Function &F, + const TargetMachine &TM) const override; + + /// Given a constant with the SectionKind, return a section that it should be + /// placed in. + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + unsigned &Align) const override; + + static XCOFF::StorageClass getStorageClassForGlobal(const GlobalObject *GO); +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_TARGETLOWERINGOBJECTFILEIMPL_H Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -268,7 +268,9 @@ }; StringMap MachOUniquingMap; + public: std::map ELFUniquingMap; + private: std::map COFFUniquingMap; std::map WasmUniquingMap; std::map XCOFFUniquingMap; Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -96,6 +96,20 @@ TargetLoweringObjectFile::Initialize(Ctx, TgtM); TM = &TgtM; + // We need to add the default sections created by initalise + // to the entry size map. + auto &ELFSectionsMap = getContext().ELFUniquingMap; + for (auto i = ELFSectionsMap.begin(); i != ELFSectionsMap.end(); i++) { + MCSectionELF *ELFSection = i->second; + if (ELFSection->getFlags() & ELF::SHF_MERGE) { + + auto i = ELFEntrySizeMap.insert(std::make_pair( + ELFEntrySizeKey{ELFSection->getSectionName(), ELFSection->getFlags(), + ELFSection->getEntrySize()}, + ELFSection->getUniqueID())); + } + } + CodeModel::Model CM = TgtM.getCodeModel(); switch (TgtM.getTargetTriple().getArch()) { @@ -589,6 +603,8 @@ Flags |= ELF::SHF_GROUP; } + unsigned int EntrySize = getEntrySizeForKind(Kind); + // A section can have at most one associated section. Put each global with // MD_associated in a unique section. unsigned UniqueID = MCContext::GenericSectionID; @@ -596,15 +612,43 @@ if (AssociatedSymbol) { UniqueID = NextUniqueID++; Flags |= ELF::SHF_LINK_ORDER; + } else { + // Mergeable globals must be placed into sections with compatible entry + // sizes. Put the global into the correct existing section or create a + // new uniqued section. + if (Flags & ELF::SHF_MERGE) { + auto i = ELFEntrySizeMap.insert(std::make_pair( + ELFEntrySizeKey{SectionName, Flags, EntrySize}, NextUniqueID)); + if (i.second) + NextUniqueID++; + UniqueID = i.first->second; + } } MCSectionELF *Section = getContext().getELFSection( - SectionName, getELFSectionType(SectionName, Kind), Flags, - getEntrySizeForKind(Kind), Group, UniqueID, AssociatedSymbol); + SectionName, getELFSectionType(SectionName, Kind), Flags, EntrySize, + Group, UniqueID, AssociatedSymbol); + // Make sure that we did not get some other section with incompatible sh_link. // This should not be possible due to UniqueID code above. assert(Section->getAssociatedSymbol() == AssociatedSymbol && "Associated symbol mismatch between sections"); + + // Mergeable globls should always be placed into mergeable sections due to the + // UniqueID code above. + if (Flags & ELF::SHF_MERGE) + assert((Section->getFlags() & ELF::SHF_MERGE) && + "Mergeable section requested but not produced"); + + // Ensure that a global is not assigned to a section with an + // incompatible entry size. This should not be possible due to the UniqueID + // code above. + if (Section->getFlags() & ELF::SHF_MERGE) + assert(Section->getEntrySize() == EntrySize && + (Section->getFlags() & ELF::SHF_STRINGS) == + (Flags & ELF::SHF_STRINGS) && + "Mismatched mergeable section entries"); + return Section; } Index: llvm/lib/Target/TargetLoweringObjectFile.cpp =================================================================== --- llvm/lib/Target/TargetLoweringObjectFile.cpp +++ llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -1,347 +1,347 @@ -//===-- llvm/Target/TargetLoweringObjectFile.cpp - Object File Info -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements classes used to handle lowerings specific to common -// object file formats. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Target/TargetLoweringObjectFile.h" -#include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Mangler.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -using namespace llvm; - -//===----------------------------------------------------------------------===// -// Generic Code -//===----------------------------------------------------------------------===// - -/// Initialize - this method must be called before any actual lowering is -/// done. This specifies the current context for codegen, and gives the -/// lowering implementations a chance to set up their default sections. -void TargetLoweringObjectFile::Initialize(MCContext &ctx, - const TargetMachine &TM) { - Ctx = &ctx; - // `Initialize` can be called more than once. - delete Mang; - Mang = new Mangler(); - InitMCObjectFileInfo(TM.getTargetTriple(), TM.isPositionIndependent(), *Ctx, - TM.getCodeModel() == CodeModel::Large); - - // Reset various EH DWARF encodings. - PersonalityEncoding = LSDAEncoding = TTypeEncoding = dwarf::DW_EH_PE_absptr; - CallSiteEncoding = dwarf::DW_EH_PE_uleb128; -} - -TargetLoweringObjectFile::~TargetLoweringObjectFile() { - delete Mang; -} - -static bool isNullOrUndef(const Constant *C) { - // Check that the constant isn't all zeros or undefs. - if (C->isNullValue() || isa(C)) - return true; - if (!isa(C)) - return false; - for (auto Operand : C->operand_values()) { - if (!isNullOrUndef(cast(Operand))) - return false; - } - return true; -} - -static bool isSuitableForBSS(const GlobalVariable *GV) { - const Constant *C = GV->getInitializer(); - - // Must have zero initializer. - if (!isNullOrUndef(C)) - return false; - - // Leave constant zeros in readonly constant sections, so they can be shared. - if (GV->isConstant()) - return false; - - // If the global has an explicit section specified, don't put it in BSS. - if (GV->hasSection()) - return false; - - // Otherwise, put it in BSS! - return true; -} - -/// IsNullTerminatedString - Return true if the specified constant (which is -/// known to have a type that is an array of 1/2/4 byte elements) ends with a -/// nul value and contains no other nuls in it. Note that this is more general -/// than ConstantDataSequential::isString because we allow 2 & 4 byte strings. -static bool IsNullTerminatedString(const Constant *C) { - // First check: is we have constant array terminated with zero - if (const ConstantDataSequential *CDS = dyn_cast(C)) { - unsigned NumElts = CDS->getNumElements(); - assert(NumElts != 0 && "Can't have an empty CDS"); - - if (CDS->getElementAsInteger(NumElts-1) != 0) - return false; // Not null terminated. - - // Verify that the null doesn't occur anywhere else in the string. - for (unsigned i = 0; i != NumElts-1; ++i) - if (CDS->getElementAsInteger(i) == 0) - return false; - return true; - } - - // Another possibility: [1 x i8] zeroinitializer - if (isa(C)) - return cast(C->getType())->getNumElements() == 1; - - return false; -} - -MCSymbol *TargetLoweringObjectFile::getSymbolWithGlobalValueBase( - const GlobalValue *GV, StringRef Suffix, const TargetMachine &TM) const { - assert(!Suffix.empty()); - - SmallString<60> NameStr; - NameStr += GV->getParent()->getDataLayout().getPrivateGlobalPrefix(); - TM.getNameWithPrefix(NameStr, GV, *Mang); - NameStr.append(Suffix.begin(), Suffix.end()); - return Ctx->getOrCreateSymbol(NameStr); -} - -MCSymbol *TargetLoweringObjectFile::getCFIPersonalitySymbol( - const GlobalValue *GV, const TargetMachine &TM, - MachineModuleInfo *MMI) const { - return TM.getSymbol(GV); -} - -void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer, - const DataLayout &, - const MCSymbol *Sym) const { -} - - -/// getKindForGlobal - This is a top-level target-independent classifier for -/// a global object. Given a global variable and information from the TM, this -/// function classifies the global in a target independent manner. This function -/// may be overridden by the target implementation. -SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO, - const TargetMachine &TM){ - assert(!GO->isDeclaration() && !GO->hasAvailableExternallyLinkage() && - "Can only be used for global definitions"); - - // Functions are classified as text sections. - if (isa(GO)) - return SectionKind::getText(); - - // Global variables require more detailed analysis. - const auto *GVar = cast(GO); - - // Handle thread-local data first. - if (GVar->isThreadLocal()) { - if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) - return SectionKind::getThreadBSS(); - return SectionKind::getThreadData(); - } - - // Variables with common linkage always get classified as common. - if (GVar->hasCommonLinkage()) - return SectionKind::getCommon(); - - // Most non-mergeable zero data can be put in the BSS section unless otherwise - // specified. - if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) { - if (GVar->hasLocalLinkage()) - return SectionKind::getBSSLocal(); - else if (GVar->hasExternalLinkage()) - return SectionKind::getBSSExtern(); - return SectionKind::getBSS(); - } - - // If the global is marked constant, we can put it into a mergable section, - // a mergable string section, or general .data if it contains relocations. - if (GVar->isConstant()) { - // If the initializer for the global contains something that requires a - // relocation, then we may have to drop this into a writable data section - // even though it is marked const. - const Constant *C = GVar->getInitializer(); - if (!C->needsRelocation()) { - // If the global is required to have a unique address, it can't be put - // into a mergable section: just drop it into the general read-only - // section instead. - if (!GVar->hasGlobalUnnamedAddr()) - return SectionKind::getReadOnly(); - - // If initializer is a null-terminated string, put it in a "cstring" - // section of the right width. - if (ArrayType *ATy = dyn_cast(C->getType())) { - if (IntegerType *ITy = - dyn_cast(ATy->getElementType())) { - if ((ITy->getBitWidth() == 8 || ITy->getBitWidth() == 16 || - ITy->getBitWidth() == 32) && - IsNullTerminatedString(C)) { - if (ITy->getBitWidth() == 8) - return SectionKind::getMergeable1ByteCString(); - if (ITy->getBitWidth() == 16) - return SectionKind::getMergeable2ByteCString(); - - assert(ITy->getBitWidth() == 32 && "Unknown width"); - return SectionKind::getMergeable4ByteCString(); - } - } - } - - // Otherwise, just drop it into a mergable constant section. If we have - // a section for this size, use it, otherwise use the arbitrary sized - // mergable section. - switch ( - GVar->getParent()->getDataLayout().getTypeAllocSize(C->getType())) { - case 4: return SectionKind::getMergeableConst4(); - case 8: return SectionKind::getMergeableConst8(); - case 16: return SectionKind::getMergeableConst16(); - case 32: return SectionKind::getMergeableConst32(); - default: - return SectionKind::getReadOnly(); - } - - } else { - // In static, ROPI and RWPI relocation models, the linker will resolve - // all addresses, so the relocation entries will actually be constants by - // the time the app starts up. However, we can't put this into a - // mergable section, because the linker doesn't take relocations into - // consideration when it tries to merge entries in the section. - Reloc::Model ReloModel = TM.getRelocationModel(); - if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI || - ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI) - return SectionKind::getReadOnly(); - - // Otherwise, the dynamic linker needs to fix it up, put it in the - // writable data.rel section. - return SectionKind::getReadOnlyWithRel(); - } - } - - // Okay, this isn't a constant. - return SectionKind::getData(); -} - -/// This method computes the appropriate section to emit the specified global -/// variable or function definition. This should not be passed external (or -/// available externally) globals. -MCSection *TargetLoweringObjectFile::SectionForGlobal( - const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { - // Select section name. - if (GO->hasSection()) - return getExplicitSectionGlobal(GO, Kind, TM); - - if (auto *GVar = dyn_cast(GO)) { - auto Attrs = GVar->getAttributes(); - if ((Attrs.hasAttribute("bss-section") && Kind.isBSS()) || - (Attrs.hasAttribute("data-section") && Kind.isData()) || - (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) || - (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())) { - return getExplicitSectionGlobal(GO, Kind, TM); - } - } - - if (auto *F = dyn_cast(GO)) { - if (F->hasFnAttribute("implicit-section-name")) - return getExplicitSectionGlobal(GO, Kind, TM); - } - - // Use default section depending on the 'type' of global - return SelectSectionForGlobal(GO, Kind, TM); -} - -MCSection *TargetLoweringObjectFile::getSectionForJumpTable( - const Function &F, const TargetMachine &TM) const { - unsigned Align = 0; - return getSectionForConstant(F.getParent()->getDataLayout(), - SectionKind::getReadOnly(), /*C=*/nullptr, - Align); -} - -bool TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection( - bool UsesLabelDifference, const Function &F) const { - // In PIC mode, we need to emit the jump table to the same section as the - // function body itself, otherwise the label differences won't make sense. - // FIXME: Need a better predicate for this: what about custom entries? - if (UsesLabelDifference) - return true; - - // We should also do if the section name is NULL or function is declared - // in discardable section - // FIXME: this isn't the right predicate, should be based on the MCSection - // for the function. - return F.isWeakForLinker(); -} - -/// Given a mergable constant with the specified size and relocation -/// information, return a section that it should be placed in. -MCSection *TargetLoweringObjectFile::getSectionForConstant( - const DataLayout &DL, SectionKind Kind, const Constant *C, - unsigned &Align) const { - if (Kind.isReadOnly() && ReadOnlySection != nullptr) - return ReadOnlySection; - - return DataSection; -} - -/// getTTypeGlobalReference - Return an MCExpr to use for a -/// reference to the specified global variable from exception -/// handling information. -const MCExpr *TargetLoweringObjectFile::getTTypeGlobalReference( - const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, - MachineModuleInfo *MMI, MCStreamer &Streamer) const { - const MCSymbolRefExpr *Ref = - MCSymbolRefExpr::create(TM.getSymbol(GV), getContext()); - - return getTTypeReference(Ref, Encoding, Streamer); -} - -const MCExpr *TargetLoweringObjectFile:: -getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding, - MCStreamer &Streamer) const { - switch (Encoding & 0x70) { - default: - report_fatal_error("We do not support this DWARF encoding yet!"); - case dwarf::DW_EH_PE_absptr: - // Do nothing special - return Sym; - case dwarf::DW_EH_PE_pcrel: { - // Emit a label to the streamer for the current position. This gives us - // .-foo addressing. - MCSymbol *PCSym = getContext().createTempSymbol(); - Streamer.EmitLabel(PCSym); - const MCExpr *PC = MCSymbolRefExpr::create(PCSym, getContext()); - return MCBinaryExpr::createSub(Sym, PC, getContext()); - } - } -} - -const MCExpr *TargetLoweringObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const { - // FIXME: It's not clear what, if any, default this should have - perhaps a - // null return could mean 'no location' & we should just do that here. - return MCSymbolRefExpr::create(Sym, *Ctx); -} - -void TargetLoweringObjectFile::getNameWithPrefix( - SmallVectorImpl &OutName, const GlobalValue *GV, - const TargetMachine &TM) const { - Mang->getNameWithPrefix(OutName, GV, /*CannotUsePrivateLabel=*/false); -} +//===-- llvm/Target/TargetLoweringObjectFile.cpp - Object File Info -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements classes used to handle lowerings specific to common +// object file formats. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Generic Code +//===----------------------------------------------------------------------===// + +/// Initialize - this method must be called before any actual lowering is +/// done. This specifies the current context for codegen, and gives the +/// lowering implementations a chance to set up their default sections. +void TargetLoweringObjectFile::Initialize(MCContext &ctx, + const TargetMachine &TM) { + Ctx = &ctx; + // `Initialize` can be called more than once. + delete Mang; + Mang = new Mangler(); + InitMCObjectFileInfo(TM.getTargetTriple(), TM.isPositionIndependent(), *Ctx, + TM.getCodeModel() == CodeModel::Large); + + // Reset various EH DWARF encodings. + PersonalityEncoding = LSDAEncoding = TTypeEncoding = dwarf::DW_EH_PE_absptr; + CallSiteEncoding = dwarf::DW_EH_PE_uleb128; +} + +TargetLoweringObjectFile::~TargetLoweringObjectFile() { + delete Mang; +} + +static bool isNullOrUndef(const Constant *C) { + // Check that the constant isn't all zeros or undefs. + if (C->isNullValue() || isa(C)) + return true; + if (!isa(C)) + return false; + for (auto Operand : C->operand_values()) { + if (!isNullOrUndef(cast(Operand))) + return false; + } + return true; +} + +static bool isSuitableForBSS(const GlobalVariable *GV) { + const Constant *C = GV->getInitializer(); + + // Must have zero initializer. + if (!isNullOrUndef(C)) + return false; + + // Leave constant zeros in readonly constant sections, so they can be shared. + if (GV->isConstant()) + return false; + + // If the global has an explicit section specified, don't put it in BSS. + if (GV->hasSection()) + return false; + + // Otherwise, put it in BSS! + return true; +} + +/// IsNullTerminatedString - Return true if the specified constant (which is +/// known to have a type that is an array of 1/2/4 byte elements) ends with a +/// nul value and contains no other nuls in it. Note that this is more general +/// than ConstantDataSequential::isString because we allow 2 & 4 byte strings. +static bool IsNullTerminatedString(const Constant *C) { + // First check: is we have constant array terminated with zero + if (const ConstantDataSequential *CDS = dyn_cast(C)) { + unsigned NumElts = CDS->getNumElements(); + assert(NumElts != 0 && "Can't have an empty CDS"); + + if (CDS->getElementAsInteger(NumElts-1) != 0) + return false; // Not null terminated. + + // Verify that the null doesn't occur anywhere else in the string. + for (unsigned i = 0; i != NumElts-1; ++i) + if (CDS->getElementAsInteger(i) == 0) + return false; + return true; + } + + // Another possibility: [1 x i8] zeroinitializer + if (isa(C)) + return cast(C->getType())->getNumElements() == 1; + + return false; +} + +MCSymbol *TargetLoweringObjectFile::getSymbolWithGlobalValueBase( + const GlobalValue *GV, StringRef Suffix, const TargetMachine &TM) const { + assert(!Suffix.empty()); + + SmallString<60> NameStr; + NameStr += GV->getParent()->getDataLayout().getPrivateGlobalPrefix(); + TM.getNameWithPrefix(NameStr, GV, *Mang); + NameStr.append(Suffix.begin(), Suffix.end()); + return Ctx->getOrCreateSymbol(NameStr); +} + +MCSymbol *TargetLoweringObjectFile::getCFIPersonalitySymbol( + const GlobalValue *GV, const TargetMachine &TM, + MachineModuleInfo *MMI) const { + return TM.getSymbol(GV); +} + +void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer, + const DataLayout &, + const MCSymbol *Sym) const { +} + + +/// getKindForGlobal - This is a top-level target-independent classifier for +/// a global object. Given a global variable and information from the TM, this +/// function classifies the global in a target independent manner. This function +/// may be overridden by the target implementation. +SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO, + const TargetMachine &TM){ + assert(!GO->isDeclaration() && !GO->hasAvailableExternallyLinkage() && + "Can only be used for global definitions"); + + // Functions are classified as text sections. + if (isa(GO)) + return SectionKind::getText(); + + // Global variables require more detailed analysis. + const auto *GVar = cast(GO); + + // Handle thread-local data first. + if (GVar->isThreadLocal()) { + if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) + return SectionKind::getThreadBSS(); + return SectionKind::getThreadData(); + } + + // Variables with common linkage always get classified as common. + if (GVar->hasCommonLinkage()) + return SectionKind::getCommon(); + + // Most non-mergeable zero data can be put in the BSS section unless otherwise + // specified. + if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) { + if (GVar->hasLocalLinkage()) + return SectionKind::getBSSLocal(); + else if (GVar->hasExternalLinkage()) + return SectionKind::getBSSExtern(); + return SectionKind::getBSS(); + } + + // If the global is marked constant, we can put it into a mergable section, + // a mergable string section, or general .data if it contains relocations. + if (GVar->isConstant()) { + // If the initializer for the global contains something that requires a + // relocation, then we may have to drop this into a writable data section + // even though it is marked const. + const Constant *C = GVar->getInitializer(); + if (!C->needsRelocation()) { + // If the global is required to have a unique address, it can't be put + // into a mergable section: just drop it into the general read-only + // section instead. + if (!GVar->hasGlobalUnnamedAddr()) + return SectionKind::getReadOnly(); + + // If initializer is a null-terminated string, put it in a "cstring" + // section of the right width. + if (ArrayType *ATy = dyn_cast(C->getType())) { + if (IntegerType *ITy = + dyn_cast(ATy->getElementType())) { + if ((ITy->getBitWidth() == 8 || ITy->getBitWidth() == 16 || + ITy->getBitWidth() == 32) && + IsNullTerminatedString(C)) { + if (ITy->getBitWidth() == 8) + return SectionKind::getMergeable1ByteCString(); + if (ITy->getBitWidth() == 16) + return SectionKind::getMergeable2ByteCString(); + + assert(ITy->getBitWidth() == 32 && "Unknown width"); + return SectionKind::getMergeable4ByteCString(); + } + } + } + + // Otherwise, just drop it into a mergable constant section. If we have + // a section for this size, use it, otherwise use the arbitrary sized + // mergable section. + switch ( + GVar->getParent()->getDataLayout().getTypeAllocSize(C->getType())) { + case 4: return SectionKind::getMergeableConst4(); + case 8: return SectionKind::getMergeableConst8(); + case 16: return SectionKind::getMergeableConst16(); + case 32: return SectionKind::getMergeableConst32(); + default: + return SectionKind::getReadOnly(); + } + + } else { + // In static, ROPI and RWPI relocation models, the linker will resolve + // all addresses, so the relocation entries will actually be constants by + // the time the app starts up. However, we can't put this into a + // mergable section, because the linker doesn't take relocations into + // consideration when it tries to merge entries in the section. + Reloc::Model ReloModel = TM.getRelocationModel(); + if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI || + ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI) + return SectionKind::getReadOnly(); + + // Otherwise, the dynamic linker needs to fix it up, put it in the + // writable data.rel section. + return SectionKind::getReadOnlyWithRel(); + } + } + + // Okay, this isn't a constant. + return SectionKind::getData(); +} + +/// This method computes the appropriate section to emit the specified global +/// variable or function definition. This should not be passed external (or +/// available externally) globals. +MCSection *TargetLoweringObjectFile::SectionForGlobal( + const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { + // Select section name. + if (GO->hasSection()) + return getExplicitSectionGlobal(GO, Kind, TM); + + if (auto *GVar = dyn_cast(GO)) { + auto Attrs = GVar->getAttributes(); + if ((Attrs.hasAttribute("bss-section") && Kind.isBSS()) || + (Attrs.hasAttribute("data-section") && Kind.isData()) || + (Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) || + (Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())) { + return getExplicitSectionGlobal(GO, Kind, TM); + } + } + + if (auto *F = dyn_cast(GO)) { + if (F->hasFnAttribute("implicit-section-name")) + return getExplicitSectionGlobal(GO, Kind, TM); + } + + // Use default section depending on the 'type' of global + return SelectSectionForGlobal(GO, Kind, TM); +} + +MCSection *TargetLoweringObjectFile::getSectionForJumpTable( + const Function &F, const TargetMachine &TM) const { + unsigned Align = 0; + return getSectionForConstant(F.getParent()->getDataLayout(), + SectionKind::getReadOnly(), /*C=*/nullptr, + Align); +} + +bool TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection( + bool UsesLabelDifference, const Function &F) const { + // In PIC mode, we need to emit the jump table to the same section as the + // function body itself, otherwise the label differences won't make sense. + // FIXME: Need a better predicate for this: what about custom entries? + if (UsesLabelDifference) + return true; + + // We should also do if the section name is NULL or function is declared + // in discardable section + // FIXME: this isn't the right predicate, should be based on the MCSection + // for the function. + return F.isWeakForLinker(); +} + +/// Given a mergable constant with the specified size and relocation +/// information, return a section that it should be placed in. +MCSection *TargetLoweringObjectFile::getSectionForConstant( + const DataLayout &DL, SectionKind Kind, const Constant *C, + unsigned &Align) const { + if (Kind.isReadOnly() && ReadOnlySection != nullptr) + return ReadOnlySection; + + return DataSection; +} + +/// getTTypeGlobalReference - Return an MCExpr to use for a +/// reference to the specified global variable from exception +/// handling information. +const MCExpr *TargetLoweringObjectFile::getTTypeGlobalReference( + const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, + MachineModuleInfo *MMI, MCStreamer &Streamer) const { + const MCSymbolRefExpr *Ref = + MCSymbolRefExpr::create(TM.getSymbol(GV), getContext()); + + return getTTypeReference(Ref, Encoding, Streamer); +} + +const MCExpr *TargetLoweringObjectFile:: +getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding, + MCStreamer &Streamer) const { + switch (Encoding & 0x70) { + default: + report_fatal_error("We do not support this DWARF encoding yet!"); + case dwarf::DW_EH_PE_absptr: + // Do nothing special + return Sym; + case dwarf::DW_EH_PE_pcrel: { + // Emit a label to the streamer for the current position. This gives us + // .-foo addressing. + MCSymbol *PCSym = getContext().createTempSymbol(); + Streamer.EmitLabel(PCSym); + const MCExpr *PC = MCSymbolRefExpr::create(PCSym, getContext()); + return MCBinaryExpr::createSub(Sym, PC, getContext()); + } + } +} + +const MCExpr *TargetLoweringObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const { + // FIXME: It's not clear what, if any, default this should have - perhaps a + // null return could mean 'no location' & we should just do that here. + return MCSymbolRefExpr::create(Sym, *Ctx); +} + +void TargetLoweringObjectFile::getNameWithPrefix( + SmallVectorImpl &OutName, const GlobalValue *GV, + const TargetMachine &TM) const { + Mang->getNameWithPrefix(OutName, GV, /*CannotUsePrivateLabel=*/false); +} Index: llvm/test/CodeGen/X86/explict-section-mergeable.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/explict-section-mergeable.ll @@ -0,0 +1,173 @@ +; RUN: llc < %s -mtriple=x86_64-linux-gnu -unique-section-names=0 -data-sections 2>&1 \ +; RUN: | FileCheck %s + +;; Test implicit section assignment for globals +; CHECK: .section .data,"aw",@progbits,unique,1 +; CHECK-NOT: .section +; CHECK: uniqified1: +; CHECK: .section .rodata.cst4,"aM",@progbits,4 +; CHECK-NOT: .section +; CHECK: implicit1: +; CHECK: .section .rodata.cst8,"aM",@progbits,8 +; CHECK-NOT: .section +; CHECK: implicit2: +; CHECK: .section .rodata.str4.4,"aMS",@progbits,4 +; CHECK-NOT: .section +; CHECK: implicit3: + +;; Check that the globals have been placed into distinct sections with +;; the same name, but different entry sizes. +; CHECK: .section .explicit,"aM",@progbits,4,unique,2 +; CHECK-NOT: .section +; CHECK: explicit1: +; CHECK: explicit2: +; CHECK: .section .explicit,"aM",@progbits,8,unique,3 +; CHECK-NOT: .section +; CHECK: explicit3: +; CHECK: explicit4: +; CHECK: .section .explicit,"aMS",@progbits,4,unique,4 +; CHECK-NOT: .section +; CHECK: explicit5: +; CHECK: explicit6: + +@uniqified1 = global i32 1 + +@implicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1] +@implicit2 = unnamed_addr constant [2 x i32] [i32 1, i32 1] +@implicit3 = unnamed_addr constant [2 x i32] [i32 1, i32 0] + +@explicit1 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit" +@explicit2 = unnamed_addr constant [2 x i16] [i16 1, i16 1] "rodata-section"=".explicit" +@explicit3 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit" +@explicit4 = unnamed_addr constant [2 x i32] [i32 1, i32 1] "rodata-section"=".explicit" +@explicit5 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit" +@explicit6 = unnamed_addr constant [2 x i32] [i32 1, i32 0] "rodata-section"=".explicit" + +;; Test implicit section assignment for globals with associated globals +; CHECK: .section .rodata.cst4,"aMo",@progbits,4,implicit1,unique,5 +; CHECK-NOT: .section +; CHECK: implicit4: +; CHECK: .section .rodata.cst8,"aMo",@progbits,8,implicit1,unique,6 +; CHECK-NOT: .section +; CHECK: implicit5: +; CHECK: .section .rodata.str4.4,"aMSo",@progbits,4,implicit1,unique,7 +; CHECK-NOT: .section +; CHECK: implicit6: + +;; Check that globals with associated globals that are explicitly assigned +;; to a section have been placed into distinct sections with the same name, but +;; different entry sizes. +; CHECK: .section .explicit,"aMo",@progbits,4,implicit1,unique,8 +; CHECK-NOT: .section +; CHECK: explicit7: +; CHECK: .section .explicit,"aMo",@progbits,4,implicit1,unique,9 +; CHECK-NOT: .section +; CHECK: explicit8: +; CHECK: .section .explicit,"aMo",@progbits,8,implicit1,unique,10 +; CHECK-NOT: .section +; CHECK: explicit9: +; CHECK: .section .explicit,"aMo",@progbits,8,implicit1,unique,11 +; CHECK-NOT: .section +; CHECK: explicit10: +; CHECK: .section .explicit,"aMSo",@progbits,4,implicit1,unique,12 +; CHECK-NOT: .section +; CHECK: explicit11: +; CHECK: .section .explicit,"aMSo",@progbits,4,implicit1,unique,13 +; CHECK-NOT: .section +; CHECK: explicit12: + +@implicit4 = unnamed_addr constant [2 x i16] [i16 1, i16 1], !associated !4 +@implicit5 = unnamed_addr constant [2 x i32] [i32 1, i32 1], !associated !4 +@implicit6 = unnamed_addr constant [2 x i32] [i32 1, i32 0], !associated !4 + +@explicit7 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", !associated !4 +@explicit8 = unnamed_addr constant [2 x i16] [i16 1, i16 1], !associated !4 "rodata-section"=".explicit" +@explicit9 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit", !associated !4 +@explicit10 = unnamed_addr constant [2 x i32] [i32 1, i32 1], !associated !4 "rodata-section"=".explicit" +@explicit11 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit", !associated !4 +@explicit12 = unnamed_addr constant [2 x i32] [i32 1, i32 0], !associated !4 "rodata-section"=".explicit" + +!4 = !{[2 x i16]* @implicit1} + +;; Test implicit section assignment for globals in distinct comdat groups +; CHECK: .section .rodata.cst4,"aGM",@progbits,4,f,comdat,unique,14 +; CHECK-NOT: .section +; CHECK: implicit7: +; CHECK: .section .rodata.cst8,"aGM",@progbits,8,g,comdat,unique,15 +; CHECK-NOT: .section +; CHECK: implicit8: +; CHECK: .section .rodata.str4.4,"aGMS",@progbits,4,h,comdat,unique,16 +; CHECK-NOT: .section +; CHECK: implicit9: + +;; Check that globals in distinct comdat groups that are explicitly assigned +;; to a section have been placed into distinct sections with the same name, but +;; different entry sizes. Due to the way that MC currently works the unique ID +;; does not have any effect here, although it appears in the assembly. +; CHECK: .section .explicit,"aGM",@progbits,4,f,comdat,unique,2 +; CHECK-NOT: .section +; CHECK: explicit13: +; CHECK: explicit14: +; CHECK: .section .explicit,"aGM",@progbits,8,g,comdat,unique,3 +; CHECK-NOT: .section +; CHECK: explicit15: +; CHECK: explicit16: +; CHECK: .section .explicit,"aGMS",@progbits,4,h,comdat,unique,4 +; CHECK-NOT: .section +; CHECK: explicit17: +; CHECK: explicit18: + +$f = comdat any +$g = comdat any +$h = comdat any + +@implicit7 = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($f) +@implicit8 = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($g) +@implicit9 = unnamed_addr constant [2 x i32] [i32 1, i32 0], comdat($h) + +@explicit13 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", comdat($f) +@explicit14 = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($f) "rodata-section"=".explicit" +@explicit15 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit", comdat($g) +@explicit16 = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($g) "rodata-section"=".explicit" +@explicit17 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit", comdat($h) +@explicit18 = unnamed_addr constant [2 x i32] [i32 1, i32 0], comdat($h) "rodata-section"=".explicit" + +;; Test implicit section assignment for globals in the same comdat group +; CHECK: .section .rodata.cst4,"aGM",@progbits,4,i,comdat,unique,17 +; CHECK-NOT: .section +; CHECK: implicit10: +; CHECK: .section .rodata.cst8,"aGM",@progbits,8,i,comdat,unique,18 +; CHECK-NOT: .section +; CHECK: implicit11: +; CHECK: .section .rodata.str4.4,"aGMS",@progbits,4,i,comdat,unique,19 +; CHECK-NOT: .section +; CHECK: implicit12: + +;; Check that globals in the same comdat group that are explicitly assigned +;; to a section have been placed into distinct sections with the same name, but +;; different entry sizes. +; CHECK: .section .explicit,"aGM",@progbits,4,i,comdat,unique,2 +; CHECK-NOT: .section +; CHECK: explicit19: +; CHECK: explicit20: +; CHECK: .section .explicit,"aGM",@progbits,8,i,comdat,unique,3 +; CHECK-NOT: .section +; CHECK: explicit21: +; CHECK: explicit22: +; CHECK: .section .explicit,"aGMS",@progbits,4,i,comdat,unique,4 +; CHECK-NOT: .section +; CHECK: explicit23: +; CHECK: explicit24: + +$i = comdat any + +@implicit10 = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($i) +@implicit11 = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($i) +@implicit12 = unnamed_addr constant [2 x i32] [i32 1, i32 0], comdat($i) + +@explicit19 = unnamed_addr constant [2 x i16] [i16 1, i16 1], section ".explicit", comdat($i) +@explicit20 = unnamed_addr constant [2 x i16] [i16 1, i16 1], comdat($i) "rodata-section"=".explicit" +@explicit21 = unnamed_addr constant [2 x i32] [i32 1, i32 1], section ".explicit", comdat($i) +@explicit22 = unnamed_addr constant [2 x i32] [i32 1, i32 1], comdat($i) "rodata-section"=".explicit" +@explicit23 = unnamed_addr constant [2 x i32] [i32 1, i32 0], section ".explicit", comdat($i) +@explicit24 = unnamed_addr constant [2 x i32] [i32 1, i32 0], comdat($i) "rodata-section"=".explicit" Index: llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp =================================================================== --- llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp +++ llvm/unittests/ExecutionEngine/Orc/LegacyRTDyldObjectLinkingLayerTest.cpp @@ -77,10 +77,12 @@ LLVMContext Context; auto M = std::make_unique("", Context); M->setTargetTriple("x86_64-unknown-linux-gnu"); - Type *Int32Ty = IntegerType::get(Context, 32); - GlobalVariable *GV = - new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, - ConstantInt::get(Int32Ty, 42), "foo"); + Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two"); + auto *GV = + new GlobalVariable(*M, StrConstant->getType(), true, + GlobalValue::ExternalLinkage, StrConstant, "foo"); + GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + GV->setAlignment(Align(1)); GV->setSection(".debug_str"); Index: llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp =================================================================== --- llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp +++ llvm/unittests/ExecutionEngine/Orc/RTDyldObjectLinkingLayerTest.cpp @@ -74,10 +74,12 @@ LLVMContext Context; auto M = std::make_unique("", Context); M->setTargetTriple("x86_64-unknown-linux-gnu"); - Type *Int32Ty = IntegerType::get(Context, 32); - GlobalVariable *GV = - new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage, - ConstantInt::get(Int32Ty, 42), "foo"); + Constant *StrConstant = ConstantDataArray::getString(Context, "forty-two"); + auto *GV = + new GlobalVariable(*M, StrConstant->getType(), true, + GlobalValue::ExternalLinkage, StrConstant, "foo"); + GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + GV->setAlignment(Align(1)); GV->setSection(".debug_str");