Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -61,6 +61,9 @@ // For tracking ARM Float Argument PCS enum class ARMVFPArgKind { Default, Base, VFP, ToolChain }; +// For -z noseparate-code, -z separate-code and -z separate-segment. +enum class SeparateSegmentKind { None, Code, All }; + struct SymbolVersion { llvm::StringRef name; bool isExternCpp; @@ -208,7 +211,6 @@ bool zOrigin; bool zRelro; bool zRodynamic; - bool zSeparateCode; bool zText; bool zRetpolineplt; bool zWxneeded; @@ -221,6 +223,7 @@ Target2Policy target2; ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default; BuildIdKind buildId = BuildIdKind::None; + SeparateSegmentKind zSeparate; ELFKind ekind = ELFNoneKind; uint16_t emachine = llvm::ELF::EM_NONE; llvm::Optional imageBase; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -376,16 +376,30 @@ return Default; } +static SeparateSegmentKind getZSeparate(opt::InputArgList &args) { + for (auto *arg : args.filtered_reverse(OPT_z)) { + StringRef v = arg->getValue(); + if (v == "noseparate-code") + return SeparateSegmentKind::None; + if (v == "separate-code") + return SeparateSegmentKind::Code; + if (v == "separate-segments") + return SeparateSegmentKind::All; + } + return SeparateSegmentKind::None; +} + static bool isKnownZFlag(StringRef s) { return s == "combreloc" || s == "copyreloc" || s == "defs" || s == "execstack" || s == "global" || s == "hazardplt" || s == "ifunc-noplt" || s == "initfirst" || s == "interpose" || s == "keep-text-section-prefix" || s == "lazy" || s == "muldefs" || - s == "separate-code" || s == "nocombreloc" || s == "nocopyreloc" || - s == "nodefaultlib" || s == "nodelete" || s == "nodlopen" || - s == "noexecstack" || s == "nokeep-text-section-prefix" || - s == "norelro" || s == "noseparate-code" || s == "notext" || - s == "now" || s == "origin" || s == "relro" || s == "retpolineplt" || + s == "separate-code" || s == "separate-segments" || + s == "nocombreloc" || s == "nocopyreloc" || s == "nodefaultlib" || + s == "nodelete" || s == "nodlopen" || s == "noexecstack" || + s == "nokeep-text-section-prefix" || s == "norelro" || + s == "noseparate-code" || s == "notext" || s == "now" || + s == "origin" || s == "relro" || s == "retpolineplt" || s == "rodynamic" || s == "text" || s == "wxneeded" || s.startswith("common-page-size") || s.startswith("max-page-size=") || s.startswith("stack-size="); @@ -939,7 +953,7 @@ config->zRelro = getZFlag(args, "relro", "norelro", true); config->zRetpolineplt = hasZOption(args, "retpolineplt"); config->zRodynamic = hasZOption(args, "rodynamic"); - config->zSeparateCode = getZFlag(args, "separate-code", "noseparate-code", false); + config->zSeparate = getZSeparate(args); config->zStackSize = args::getZOptionValue(args, OPT_z, "stack-size", 0); config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -588,7 +588,8 @@ return; if (!config->oFormatBinary) { - writeTrapInstr(); + if (config->zSeparate != SeparateSegmentKind::None) + writeTrapInstr(); writeHeader(); writeSections(); } else { @@ -2220,8 +2221,8 @@ // TODO Enable this technique on all targets. bool enable = config->emachine != EM_HEXAGON; - if (!enable || - (config->zSeparateCode && prev && + if (!enable || config->zSeparate == SeparateSegmentKind::All || + (config->zSeparate == SeparateSegmentKind::Code && prev && (prev->p_flags & PF_X) != (p->p_flags & PF_X)) || cmd->type == SHT_LLVM_PART_EHDR) cmd->addrExpr = [] { @@ -2330,7 +2331,8 @@ // If this is a last section of the last executable segment and that // segment is the last loadable segment, align the offset of the // following section to avoid loading non-segments parts of the file. - if (config->zSeparateCode && lastRX && lastRX->lastSec == sec) + if (config->zSeparate != SeparateSegmentKind::None && lastRX && + lastRX->lastSec == sec) off = alignTo(off, config->commonPageSize); } @@ -2602,9 +2604,6 @@ // We'll leave other pages in segments as-is because the rest will be // overwritten by output sections. template void Writer::writeTrapInstr() { - if (!config->zSeparateCode) - return; - for (Partition &part : partitions) { // Fill the last page. for (PhdrEntry *p : part.phdrs) Index: test/ELF/fill-trap.s =================================================================== --- test/ELF/fill-trap.s +++ test/ELF/fill-trap.s @@ -12,6 +12,11 @@ # RUN: llvm-readobj -l %t | FileCheck %s --check-prefixes=CHECK,PAD # RUN: od -Ax -x -N16 -j0x1ff0 %t | FileCheck %s --check-prefix=FILL +## -z separate-segments pads all segments, including the text segment. +# RUN: ld.lld %t.o -z separate-segments -o %t +# RUN: llvm-readobj -l %t | FileCheck %s --check-prefixes=CHECK,PAD +# RUN: od -Ax -x -N16 -j0x1ff0 %t | FileCheck %s --check-prefix=FILL + # RUN: ld.lld %t.o -z separate-code -z noseparate-code -o %t # RUN: llvm-readobj -l %t | FileCheck %s --check-prefixes=CHECK,NOPAD Index: test/ELF/separate-segments.s =================================================================== --- /dev/null +++ test/ELF/separate-segments.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o + +## -z noseparate-code is the default. All PT_LOAD can have overlapping p_offset +## ranges at runtime. +# RUN: ld.lld -pie %t.o -o %t +# RUN: llvm-readelf -l %t | FileCheck --check-prefix=NONE %s +# NONE: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000 +# NONE-NEXT: LOAD 0x000248 0x0000000000001248 0x0000000000001248 0x000001 0x000001 R E 0x1000 +# NONE-NEXT: LOAD 0x000250 0x0000000000002250 0x0000000000002250 0x000080 0x000080 RW 0x1000 +# NONE-NEXT: LOAD 0x0002d0 0x00000000000032d0 0x00000000000032d0 0x000001 0x000001 RW 0x1000 + +## -z separate-code makes text segment (RX) separate. +## The two RW can have overlapping p_offset ranges at runtime. +# RUN: ld.lld -pie %t.o -z separate-code -o %t +# RUN: llvm-readelf -l %t | FileCheck --check-prefix=CODE %s +# CODE: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000 +# CODE-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000 +# CODE-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000080 0x000080 RW 0x1000 +# CODE-NEXT: LOAD 0x002080 0x0000000000003080 0x0000000000003080 0x000001 0x000001 RW 0x1000 + +## -z separate-segments makes all segments separate. +# RUN: ld.lld -pie %t.o -z separate-segments -o %t +# RUN: llvm-readelf -l %t | FileCheck --check-prefix=ALL %s +# ALL: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000245 0x000245 R 0x1000 +# ALL-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000001 0x000001 R E 0x1000 +# ALL-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x000080 0x000080 RW 0x1000 +# ALL-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000003000 0x000001 0x000001 RW 0x1000 + +nop + +.data +.byte 0