// See if a region can be found by matching section flags.
for (auto &pair : memoryRegions) {
MemoryRegion *m = pair.second;
- if ((m->flags & sec->flags) && (m->negFlags & sec->flags) == 0)
+ if (m->compatibleWith(sec->flags))
return {m, nullptr};
}
// MEMORY command.
struct MemoryRegion {
MemoryRegion(StringRef name, Expr origin, Expr length, uint32_t flags,
- uint32_t negFlags)
+ uint32_t invFlags, uint32_t negFlags, uint32_t negInvFlags)
: name(std::string(name)), origin(origin), length(length), flags(flags),
- negFlags(negFlags) {}
+ invFlags(invFlags), negFlags(negFlags), negInvFlags(negInvFlags) {}
std::string name;
Expr origin;
Expr length;
+ // A section can be assigned to the region if any of these ELF section flags
+ // are set...
uint32_t flags;
+ // ... or any of these flags are not set.
+ // For example, the memory region attribute "r" maps to SHF_WRITE.
+ uint32_t invFlags;
+ // A section cannot be assigned to the region if any of these ELF section
+ // flags are set...
uint32_t negFlags;
+ // ... or any of these flags are not set.
+ // For example, the memory region attribute "!r" maps to SHF_WRITE.
+ uint32_t negInvFlags;
uint64_t curPos = 0;
+
+ bool compatibleWith(uint32_t secFlags) const {
+ if ((secFlags & negFlags) || (~secFlags & negInvFlags))
+ return false;
+ return (secFlags & flags) || (~secFlags & invFlags);
+ }
};
// This struct represents one section match pattern in SECTIONS() command.
Expr getPageSize();
Expr readMemoryAssignment(StringRef, StringRef, StringRef);
- std::pair<uint32_t, uint32_t> readMemoryAttributes();
+ void readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
+ uint32_t &negFlags, uint32_t &negInvFlags);
Expr combine(StringRef op, Expr l, Expr r);
Expr readExpr();
}
uint32_t flags = 0;
+ uint32_t invFlags = 0;
uint32_t negFlags = 0;
+ uint32_t negInvFlags = 0;
if (consume("(")) {
- std::tie(flags, negFlags) = readMemoryAttributes();
+ readMemoryAttributes(flags, invFlags, negFlags, negInvFlags);
expect(")");
}
expect(":");
Expr length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, negFlags);
+ MemoryRegion *mr = make<MemoryRegion>(tok, origin, length, flags, invFlags,
+ negFlags, negInvFlags);
if (!script->memoryRegions.insert({tok, mr}).second)
setError("region '" + tok + "' already defined");
}
// This function parses the attributes used to match against section
// flags when placing output sections in a memory region. These flags
// are only used when an explicit memory region name is not used.
-std::pair<uint32_t, uint32_t> ScriptParser::readMemoryAttributes() {
- uint32_t flags = 0;
- uint32_t negFlags = 0;
+void ScriptParser::readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
+ uint32_t &negFlags,
+ uint32_t &negInvFlags) {
bool invert = false;
for (char c : next().lower()) {
- uint32_t flag = 0;
- if (c == '!')
+ if (c == '!') {
invert = !invert;
- else if (c == 'w')
- flag = SHF_WRITE;
+ std::swap(flags, negFlags);
+ std::swap(invFlags, negInvFlags);
+ continue;
+ }
+ if (c == 'w')
+ flags |= SHF_WRITE;
else if (c == 'x')
- flag = SHF_EXECINSTR;
+ flags |= SHF_EXECINSTR;
else if (c == 'a')
- flag = SHF_ALLOC;
- else if (c != 'r')
+ flags |= SHF_ALLOC;
+ else if (c == 'r')
+ invFlags |= SHF_WRITE;
+ else
setError("invalid memory region attribute");
+ }
- if (invert)
- negFlags |= flag;
- else
- flags |= flag;
+ if (invert) {
+ std::swap(flags, negFlags);
+ std::swap(invFlags, negInvFlags);
}
- return {flags, negFlags};
}
void elf::readLinkerScript(MemoryBufferRef mb) {
--- /dev/null
+REQUIRES: x86
+
+RUN: split-file %s %ts
+RUN: llvm-mc -filetype=obj -triple=x86_64 %ts/s -o %t.o
+
+## Check assigning sections to memory regions by attributes.
+
+#--- s
+ .text
+ .zero 8
+
+ .rodata
+ .zero 8
+
+ .data
+ .zero 8
+
+#--- t1
+## Check memory region attribute 'a'.
+
+# RUN: ld.lld -o %t1 -T %ts/t1 %t.o
+# RUN: llvm-readelf -S %t1 | FileCheck %s --check-prefix=TEST1
+
+# TEST1: Name Type Address
+# TEST1: .text PROGBITS 0000000000002000
+# TEST1-NEXT: .rodata PROGBITS 0000000000002008
+# TEST1-NEXT: .data PROGBITS 0000000000002010
+
+MEMORY
+{
+ ## All sections have SHF_ALLOC attribute, so no one can be added here.
+ NOMEM (rwx!a) : org = 0x1000, l = 1K
+ ## All sections are assigned to this memory region.
+ MEM (a) : org = 0x2000, l = 1K
+}
+
+SECTIONS
+{
+ .text : { *(.text) }
+ .rodata : { *(.rodata) }
+ .data : { *(.data) }
+}
+
+#--- t2
+## Check that memory region attributes 'r', 'w', and 'x' are supported both in
+## positive and negative forms.
+
+# RUN: ld.lld -o %t2 -T %ts/t2 %t.o
+# RUN: llvm-readelf -S %t2 | FileCheck %s --check-prefix=TEST2
+
+# TEST2: Name Type Address
+# TEST2: .text PROGBITS 0000000000004000
+# TEST2-NEXT: .rodata PROGBITS 0000000000003000
+# TEST2-NEXT: .data PROGBITS 0000000000002000
+
+MEMORY
+{
+ ## While all sections are allocatable, '.text' and '.rodata' are read-only and
+ ## '.data' is writable, so no sections should be assigned to this region.
+ NOMEM (a!rw) : org = 0x1000, l = 1K
+ ## Only writable section '.data' is allowed here.
+ RAM (w) : org = 0x2000, l = 1K
+ ## Executable sections are not allowed here, so only '.rodata' should be
+ ## assigned to the region.
+ ROM (r!x) : org = 0x3000, l = 1K
+ ## An executable section '.text' comes here.
+ EXEC (x) : org = 0x4000, l = 1K
+}
+
+SECTIONS
+{
+ .text : { *(.text) }
+ .rodata : { *(.rodata) }
+ .data : { *(.data) }
+}