diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -412,9 +412,7 @@ // XCOFF specific sections MCSection *getTOCBaseSection() const { return TOCBaseSection; } - MCSection *getEHFrameSection() { - return EHFrameSection; - } + MCSection *getEHFrameSection() const { return EHFrameSection; } enum Environment { IsMachO, IsELF, IsCOFF, IsWasm, IsXCOFF }; Environment getObjectFileType() const { return Env; } diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -507,6 +507,199 @@ return Flags; } +/// Return true if one of the default sections +static bool isDefaultELFSection(const MCContext &C, const MCSectionELF &S) { + const MCObjectFileInfo &OFI = *C.getObjectFileInfo(); + if (&S == OFI.getTextSection()) + return true; + if (&S == OFI.getDataSection()) + return true; + if (&S == OFI.getBSSSection()) + return true; + if (&S == OFI.getReadOnlySection()) + return true; + if (&S == OFI.getCompactUnwindSection()) + return true; + if (&S == OFI.getDwarfAbbrevSection()) + return true; + if (&S == OFI.getDwarfInfoSection()) + return true; + if (&S == OFI.getDwarfLineSection()) + return true; + if (&S == OFI.getDwarfLineStrSection()) + return true; + if (&S == OFI.getDwarfFrameSection()) + return true; + if (&S == OFI.getDwarfPubNamesSection()) + return true; + if (&S == OFI.getDwarfPubTypesSection()) + return true; + if (&S == OFI.getDwarfGnuPubNamesSection()) + return true; + if (&S == OFI.getDwarfGnuPubTypesSection()) + return true; + if (&S == OFI.getDwarfDebugInlineSection()) + return true; + if (&S == OFI.getDwarfStrSection()) + return true; + if (&S == OFI.getDwarfLocSection()) + return true; + if (&S == OFI.getDwarfARangesSection()) + return true; + if (&S == OFI.getDwarfRangesSection()) + return true; + if (&S == OFI.getDwarfRnglistsSection()) + return true; + if (&S == OFI.getDwarfLoclistsSection()) + return true; + if (&S == OFI.getDwarfMacinfoSection()) + return true; + if (&S == OFI.getDwarfMacroSection()) + return true; + if (&S == OFI.getDwarfDebugNamesSection()) + return true; + if (&S == OFI.getDwarfAccelNamesSection()) + return true; + if (&S == OFI.getDwarfAccelObjCSection()) + return true; + if (&S == OFI.getDwarfAccelNamespaceSection()) + return true; + if (&S == OFI.getDwarfAccelTypesSection()) + return true; + if (&S == OFI.getDwarfInfoDWOSection()) + return true; + // if(S == OFI.getDwarfTypesSection(hash) return true; + if (&S == OFI.getDwarfTypesDWOSection()) + return true; + if (&S == OFI.getDwarfAbbrevDWOSection()) + return true; + if (&S == OFI.getDwarfStrDWOSection()) + return true; + if (&S == OFI.getDwarfLineDWOSection()) + return true; + if (&S == OFI.getDwarfLocDWOSection()) + return true; + if (&S == OFI.getDwarfStrOffDWOSection()) + return true; + if (&S == OFI.getDwarfStrOffSection()) + return true; + if (&S == OFI.getDwarfAddrSection()) + return true; + if (&S == OFI.getDwarfRnglistsDWOSection()) + return true; + if (&S == OFI.getDwarfLoclistsDWOSection()) + return true; + if (&S == OFI.getDwarfMacroDWOSection()) + return true; + if (&S == OFI.getDwarfMacinfoDWOSection()) + return true; + if (&S == OFI.getDwarfCUIndexSection()) + return true; + if (&S == OFI.getDwarfTUIndexSection()) + return true; + if (&S == OFI.getDwarfSwiftASTSection()) + return true; + if (&S == OFI.getCOFFDebugSymbolsSection()) + return true; + if (&S == OFI.getCOFFDebugTypesSection()) + return true; + if (&S == OFI.getCOFFGlobalTypeHashesSection()) + return true; + if (&S == OFI.getTLSExtraDataSection()) + return true; + if (&S == OFI.getTLSDataSection()) + return true; + if (&S == OFI.getTLSBSSSection()) + return true; + if (&S == OFI.getStackMapSection()) + return true; + if (&S == OFI.getFaultMapSection()) + return true; + if (&S == OFI.getRemarksSection()) + return true; + if (&S == OFI.getStackSizesSection(*OFI.getTextSection())) + return true; + if (&S == OFI.getBBAddrMapSection(*OFI.getTextSection())) + return true; + if (&S == OFI.getPseudoProbeSection(OFI.getTextSection())) + return true; + // if(S == OFI.getPseudoProbeDescSection(function) return true; + if (&S == OFI.getDataRelROSection()) + return true; + if (&S == OFI.getMergeableConst4Section()) + return true; + if (&S == OFI.getMergeableConst8Section()) + return true; + if (&S == OFI.getMergeableConst16Section()) + return true; + if (&S == OFI.getMergeableConst32Section()) + return true; + if (&S == OFI.getTLSTLVSection()) + return true; + if (&S == OFI.getTLSThreadInitSection()) + return true; + if (&S == OFI.getCStringSection()) + return true; + if (&S == OFI.getUStringSection()) + return true; + if (&S == OFI.getTextCoalSection()) + return true; + if (&S == OFI.getConstTextCoalSection()) + return true; + if (&S == OFI.getConstDataSection()) + return true; + if (&S == OFI.getDataCoalSection()) + return true; + if (&S == OFI.getConstDataCoalSection()) + return true; + if (&S == OFI.getDataCommonSection()) + return true; + if (&S == OFI.getDataBSSSection()) + return true; + if (&S == OFI.getFourByteConstantSection()) + return true; + if (&S == OFI.getEightByteConstantSection()) + return true; + if (&S == OFI.getSixteenByteConstantSection()) + return true; + if (&S == OFI.getLazySymbolPointerSection()) + return true; + if (&S == OFI.getNonLazySymbolPointerSection()) + return true; + if (&S == OFI.getThreadLocalPointerSection()) + return true; + if (&S == OFI.getDrectveSection()) + return true; + if (&S == OFI.getPDataSection()) + return true; + if (&S == OFI.getXDataSection()) + return true; + if (&S == OFI.getSXDataSection()) + return true; + if (&S == OFI.getGFIDsSection()) + return true; + if (&S == OFI.getGIATsSection()) + return true; + if (&S == OFI.getGLJMPSection()) + return true; + if (&S == OFI.getTOCBaseSection()) + return true; + if (&S == OFI.getEHFrameSection()) + return true; + return false; +} + +/// Return true if the section is compatible with the given flags. +static bool flagsCompatible(const unsigned OldFlags, const unsigned NewFlags) { + // WRITE and EXECINSTR are not compatible + if (OldFlags & ELF::SHF_EXECINSTR && NewFlags & ELF::SHF_WRITE) + return false; + if (OldFlags & ELF::SHF_WRITE && NewFlags & ELF::SHF_EXECINSTR) + return false; + + return true; +} + static const Comdat *getELFComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) @@ -726,6 +919,29 @@ assert(Section->getLinkedToSymbol() == LinkedToSym && "Associated symbol mismatch between sections"); + // Update the seen flags of user defined sections, raise an error if invalid + // combinations are seen. Don't update flags of standard sections (.text etc). + if (Section->getFlags() != Flags && + !isDefaultELFSection(getContext(), *Section)) { + if (flagsCompatible(Section->getFlags(), Flags)) { + // If all flags are compatible then add any new ones to the section. + const auto MergedFlags = Section->getFlags() | Flags; + if (MergedFlags != Section->getFlags()) { + Section->setFlags(MergedFlags); + GO->getContext().diagnose(LoweringDiagnosticInfo( + "Symbol " + GO->getName() + ": updating section flags: " + + SectionName + " 0x" + utohexstr(MergedFlags), + DS_Remark)); + } + } else { + GO->getContext().diagnose(LoweringDiagnosticInfo( + "Symbol '" + GO->getName() + + "' implies incompatible flags for section '" + SectionName + + "'. Old: 0x" + utohexstr(Section->getFlags()) + ", New: 0x" + + utohexstr(Flags))); + } + } + if (!getContext().getAsmInfo()->useIntegratedAssembler()) { // If we are not using the integrated assembler then this symbol might have // been placed in an incompatible mergeable section. Emit an error if this diff --git a/llvm/test/CodeGen/AArch64/aarch64-section-flags-incompatible.ll b/llvm/test/CodeGen/AArch64/aarch64-section-flags-incompatible.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/aarch64-section-flags-incompatible.ll @@ -0,0 +1,43 @@ +; RUN: not llc -mtriple=aarch64-arm-none-eabi %s -o - 2>&1 | FileCheck %s +; RUN: not llc -mtriple=aarch64-arm-none-eabi %s -o - 2> /dev/null | FileCheck %s --check-prefix=ASSEMBLY + +; User creates globals with SHF_WRITE and SHF_EXECINSTR +@rw_s1 = global i32 10, section "s1_ax", align 4 +define i32 @fn_s1() section "s1_ax" { + entry: + ret i32 0 +} +; CHECK: error: Symbol 'rw_s1' implies incompatible flags for section 's1_ax'. Old: 0x6, New: 0x3 + +; This is fine; constant can live in SHF_EXECINSTR section +@ro_s2 = constant i32 10, section "s2_ax", align 4 +define i32 @fn_s2() section "s2_ax" { + entry: + ret i32 0 +} +; CHECK-NOT: error: Symbol 'ro_s2' implies incompatible flags for section 's2_ax'. +; CHECK-NOT: remark: Symbol ro_s2: updating section flags +; ASSEMBLY: .section s2_ax,"ax",@progbits +; ASSEMBLY: .section s2_ax,"ax",@progbits + +; This is also fine; constant can live in SHF_WRITE +@ro_s3 = constant i32 10, section "s3_aw", align 4 +@rw_s3 = global i32 10, section "s3_aw", align 4 +; CHECK-NOT: error: Symbol 'rw_s3' implies incompatible flags for section 's3_aw'. +; CHECK: remark: Symbol rw_s3: updating section flags: s3_aw 0x3 +; ASSEMBLY: .section s3_aw,"a",@progbits + +; This is fine; .text is read only, but the flags shouldn't change +@ro_text = constant i32 10, section ".text", align 4 +; CHECK-NOT: error: Symbol 'ro_text' implies incompatible flags for section '.text'. +; CHECK-NOT: remark: Symbol ro_text: updating section flags: .text + +; This is fine; .text is read only, but mutable globals are not necessarily written to +@rw_text = global i32 10, section ".text", align 4 +; CHECK-NOT: error: Symbol 'rw_text' implies incompatible flags for section '.text'. Old: 0x6, New: 0x3 +; CHECK-NOT: remark: Symbol rw_text: updating section flags: .text + +; This is fine; .data is writeable, but the flags shouldn't change and constants are allowed +@ro_data = constant i32 10, section ".data", align 4 +; CHECK-NOT: error: Symbol 'ro_data' implies incompatible flags for section '.data'. +; CHECK-NOT: remark: Symbol ro_data: updating section flags: .data