summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/OutputSections.cpp14
-rw-r--r--lld/test/ELF/arm-execute-only.s38
2 files changed, 49 insertions, 3 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 4facba60e9e..6e94baa5d1b 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -45,7 +45,9 @@ OutputSection *Out::FiniArray;
std::vector<OutputSection *> elf::OutputSections;
uint32_t OutputSection::getPhdrFlags() const {
- uint32_t Ret = PF_R;
+ uint32_t Ret = 0;
+ if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE))
+ Ret |= PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
if (Flags & SHF_EXECINSTR)
@@ -110,10 +112,11 @@ static bool canMergeToProgbits(unsigned Type) {
void OutputSection::addSection(InputSection *IS) {
if (!Live) {
// If IS is the first section to be added to this section,
- // initialize Type and Entsize from IS.
+ // initialize Type, Entsize and flags from IS.
Live = true;
Type = IS->Type;
Entsize = IS->Entsize;
+ Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS)))
@@ -133,7 +136,12 @@ void OutputSection::addSection(InputSection *IS) {
}
IS->Parent = this;
- Flags |= IS->Flags;
+ uint64_t AndMask = Config->EMachine == EM_ARM ? SHF_ARM_PURECODE : 0;
+ uint64_t OrMask = ~AndMask;
+ uint64_t AndFlags = (Flags & IS->Flags) & AndMask;
+ uint64_t OrFlags = (Flags | IS->Flags) & OrMask;
+ Flags = AndFlags | OrFlags;
+
Alignment = std::max(Alignment, IS->Alignment);
IS->OutSecOff = Size++;
diff --git a/lld/test/ELF/arm-execute-only.s b/lld/test/ELF/arm-execute-only.s
new file mode 100644
index 00000000000..01de9d53244
--- /dev/null
+++ b/lld/test/ELF/arm-execute-only.s
@@ -0,0 +1,38 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %s -o %t.o
+// RUN: ld.lld %t.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck %s
+
+// RUN: ld.lld %t.o %t.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck %s
+
+// RUN: echo ".section .foo,\"ax\"; \
+// RUN: bx lr" > %t.s
+// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %t.s -o %t2.o
+// RUN: ld.lld %t.o %t2.o -o %t.so -shared
+// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF %s
+
+// CHECK-NOT: LOAD
+// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x00169 0x00169 R 0x1000
+// CHECK: LOAD 0x001000 0x00001000 0x00001000 0x{{.*}} 0x{{.*}} R E 0x1000
+// CHECK: LOAD 0x002000 0x00002000 0x00002000 0x{{.*}} 0x{{.*}} E 0x1000
+// CHECK: LOAD 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000
+// CHECK-NOT: LOAD
+
+// CHECK: 01 .dynsym .gnu.hash .hash .dynstr
+// CHECK: 02 .text
+// CHECK: 03 .foo
+// CHECK: 04 .dynamic
+
+// DIFF-NOT: LOAD
+// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x00149 0x00149 R 0x1000
+// DIFF: LOAD 0x001000 0x00001000 0x00001000 0x0000c 0x0000c R E 0x1000
+// DIFF: LOAD 0x002000 0x00002000 0x00002000 0x00038 0x00038 RW 0x1000
+// DIFF-NOT: LOAD
+
+// DIFF: 01 .dynsym .gnu.hash .hash .dynstr
+// DIFF: 02 .text .foo
+// DIFF: 03 .dynamic
+
+ bx lr
+ .section .foo,"axy"
+ bx lr
OpenPOWER on IntegriCloud