Index: include/llvm/MC/MCELFObjectWriter.h =================================================================== --- include/llvm/MC/MCELFObjectWriter.h +++ include/llvm/MC/MCELFObjectWriter.h @@ -13,6 +13,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include @@ -92,6 +93,8 @@ virtual void sortRelocs(const MCAssembler &Asm, std::vector &Relocs); + virtual void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec); + /// \name Accessors /// @{ uint8_t getOSABI() const { return OSABI; } Index: include/llvm/MC/MCSection.h =================================================================== --- include/llvm/MC/MCSection.h +++ include/llvm/MC/MCSection.h @@ -78,6 +78,10 @@ /// Whether this section has had instructions emitted into it. bool HasInstructions : 1; + /// Whether this section has had data emitted into it. + /// Right now this is only used by the ARM backend. + bool HasData : 1; + bool IsRegistered : 1; MCDummyFragment DummyFragment; @@ -137,6 +141,9 @@ bool hasInstructions() const { return HasInstructions; } void setHasInstructions(bool Value) { HasInstructions = Value; } + bool hasData() const { return HasData; } + void setHasData(bool Value) { HasData = Value; } + bool isRegistered() const { return IsRegistered; } void setIsRegistered(bool Value) { IsRegistered = Value; } Index: lib/MC/ELFObjectWriter.cpp =================================================================== --- lib/MC/ELFObjectWriter.cpp +++ lib/MC/ELFObjectWriter.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCFragment.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" @@ -1107,6 +1108,8 @@ SectionIndexMap[RelSection] = addToSectionTable(RelSection); Relocations.push_back(RelSection); } + + OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section); } MCSectionELF *CGProfileSection = nullptr; Index: lib/MC/MCELFObjectTargetWriter.cpp =================================================================== --- lib/MC/MCELFObjectTargetWriter.cpp +++ lib/MC/MCELFObjectTargetWriter.cpp @@ -26,3 +26,6 @@ MCELFObjectTargetWriter::sortRelocs(const MCAssembler &Asm, std::vector &Relocs) { } + +void MCELFObjectTargetWriter::addTargetSectionFlags(MCContext &Ctx, + MCSectionELF &Sec) {} Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -496,6 +496,12 @@ MCDataFragment *DF = getOrCreateDataFragment(); flushPendingLabels(DF, DF->getContents().size()); DF->getContents().append(Data.begin(), Data.end()); + + // EmitBytes might not cover all possible ways we emit data (or could be used + // to emit executable code in some cases), but is the best method we have + // right now for checking this. + MCSection *Sec = getCurrentSectionOnly(); + Sec->setHasData(true); } void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment, Index: lib/MC/MCSection.cpp =================================================================== --- lib/MC/MCSection.cpp +++ lib/MC/MCSection.cpp @@ -23,7 +23,8 @@ MCSection::MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin) : Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false), - IsRegistered(false), DummyFragment(this), Variant(V), Kind(K) {} + HasData(false), IsRegistered(false), DummyFragment(this), Variant(V), + Kind(K) {} MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) { if (!End) Index: lib/Target/ARM/ARMTargetObjectFile.cpp =================================================================== --- lib/Target/ARM/ARMTargetObjectFile.cpp +++ lib/Target/ARM/ARMTargetObjectFile.cpp @@ -32,7 +32,8 @@ const TargetMachine &TM) { const ARMBaseTargetMachine &ARM_TM = static_cast(TM); bool isAAPCS_ABI = ARM_TM.TargetABI == ARMBaseTargetMachine::ARMABI::ARM_ABI_AAPCS; - // genExecuteOnly = ARM_TM.getSubtargetImpl()->genExecuteOnly(); + bool genExecuteOnly = + ARM_TM.getMCSubtargetInfo()->hasFeature(ARM::FeatureExecuteOnly); TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(isAAPCS_ABI); @@ -40,6 +41,17 @@ if (isAAPCS_ABI) { LSDASection = nullptr; } + + // Make code section unreadable when in execute-only mode + if (genExecuteOnly) { + unsigned Type = ELF::SHT_PROGBITS; + unsigned Flags = + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_ARM_PURECODE; + // Since we cannot modify flags for an existing section, we create a new + // section with the right flags, and use 0 as the unique ID for + // execute-only text + TextSection = Ctx.getELFSection(".text", Type, Flags, 0, "", 0U); + } } const MCExpr *ARMElfTargetObjectFile::getTTypeGlobalReference( Index: lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" @@ -40,6 +41,8 @@ bool needsRelocateWithSymbol(const MCSymbol &Sym, unsigned Type) const override; + + void addTargetSectionFlags(MCContext &Ctx, MCSectionELF &Sec) override; }; } // end anonymous namespace @@ -236,6 +239,21 @@ } } +void ARMELFObjectWriter::addTargetSectionFlags(MCContext &Ctx, + MCSectionELF &Sec) { + // The mix of execute-only and non-execute-only at link time is + // non-execute-only. To avoid the empty implicitly created .text + // section from making the whole .text section non-execute-only, we + // mark it execute-only if it is empty and there is at least one + // execute-only section in the object. + MCSectionELF *TextSection = + static_cast(Ctx.getObjectFileInfo()->getTextSection()); + if (Sec.getKind().isExecuteOnly() && !TextSection->hasInstructions() && + !TextSection->hasData()) { + TextSection->setFlags(TextSection->getFlags() | ELF::SHF_ARM_PURECODE); + } +} + std::unique_ptr llvm::createARMELFObjectWriter(uint8_t OSABI) { return llvm::make_unique(OSABI); Index: test/CodeGen/ARM/execute-only.ll =================================================================== --- test/CodeGen/ARM/execute-only.ll +++ test/CodeGen/ARM/execute-only.ll @@ -2,6 +2,9 @@ ; RUN: llc -mtriple=thumbv7m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s ; RUN: llc -mtriple=thumbv8m.main-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s +; CHECK-NOT: {{^ *}}.text{{$}} +; CHECK: .section .text,"axy",%progbits,unique,0 + @var = global i32 0 define i32 @global() minsize { Index: test/MC/ARM/elf-execute-only-section.ll =================================================================== --- /dev/null +++ test/MC/ARM/elf-execute-only-section.ll @@ -0,0 +1,13 @@ +; RUN: llc < %s -mtriple=thumbv8m.base-eabi -mattr=+execute-only -filetype=obj %s -o - | \ +; RUN: llvm-readelf -s | FileCheck %s +; RUN: llc < %s -mtriple=thumbv8m.main-eabi -mattr=+execute-only -filetype=obj %s -o - | \ +; RUN: llvm-readelf -s | FileCheck %s +; RUN: llc < %s -mtriple=thumbv7m-eabi -mattr=+execute-only -filetype=obj %s -o - | \ +; RUN: llvm-readelf -s | FileCheck %s + +; CHECK-NOT: {{.text[ ]+PROGBITS[ ]+[0-9]+ [0-9]+ [0-9]+ [0-9]+ AX[^p]}} +; CHECK: {{.text[ ]+PROGBITS[ ]+[0-9]+ [0-9]+ [0-9]+ [0-9]+ AXp}} +define void @test_func() { +entry: + ret void +} Index: test/MC/ELF/ARM/execute-only-populated-text-section.s =================================================================== --- /dev/null +++ test/MC/ELF/ARM/execute-only-populated-text-section.s @@ -0,0 +1,27 @@ +// RUN: llvm-mc -filetype=obj -triple thumbv7m-arm-linux-gnu %s -o - \ +// RUN: | llvm-readobj -s -t | FileCheck %s + + .text + bx lr + + .section .text.foo,"axy" + bx lr + +// CHECK: Section { +// CHECK: Name: .text +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_EXECINSTR (0x4) +// CHECK-NEXT: ] +// CHECK: } + +// CHECK: Section { +// CHECK: Name: .text.foo +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x20000006) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_ARM_PURECODE (0x20000000) +// CHECK-NEXT: SHF_EXECINSTR (0x4) +// CHECK-NEXT: ] +// CHECK: } Index: test/MC/ELF/ARM/execute-only-section.s =================================================================== --- test/MC/ELF/ARM/execute-only-section.s +++ test/MC/ELF/ARM/execute-only-section.s @@ -20,8 +20,9 @@ // CHECK: Section { // CHECK: Name: .text (16) // CHECK-NEXT: Type: SHT_PROGBITS (0x1) -// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: Flags [ (0x20000006) // CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_ARM_PURECODE (0x20000000) // CHECK-NEXT: SHF_EXECINSTR (0x4) // CHECK-NEXT: ] // CHECK: Size: 0 Index: test/MC/ELF/ARM/execute-only-text-section-data.s =================================================================== --- /dev/null +++ test/MC/ELF/ARM/execute-only-text-section-data.s @@ -0,0 +1,27 @@ +// RUN: llvm-mc -filetype=obj -triple thumbv7m-arm-linux-gnu %s -o - \ +// RUN: | llvm-readobj -s -t | FileCheck %s + + .text + .ascii "test" + + .section .text.foo,"axy" + bx lr + +// CHECK: Section { +// CHECK: Name: .text +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_EXECINSTR (0x4) +// CHECK-NEXT: ] +// CHECK: } + +// CHECK: Section { +// CHECK: Name: .text.foo +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x20000006) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_ARM_PURECODE (0x20000000) +// CHECK-NEXT: SHF_EXECINSTR (0x4) +// CHECK-NEXT: ] +// CHECK: }