mirror of
https://github.com/intel/llvm.git
synced 2026-01-26 21:29:36 +08:00
[lld][AArch64] Add support for GCS (#90732)
This adds the -z gcs and -z gcs-report options, which behave similarly to -z shtk and -z cet-report, except that -z gcs accepts a parameter: * -z gcs=implicit is the default behaviour, where the GCS bit is inferred from the input objects. * -z gcs=never clears the GCS bit, ignoring the input objects. * -z gcs=always sets the GCS bit, ignoring the input objects. This is so that there's a means of explicitly disabling GCS even when all input objects have the GCS bit set.
This commit is contained in:
@@ -102,6 +102,9 @@ enum class GnuStackKind { None, Exec, NoExec };
|
||||
// For --lto=
|
||||
enum LtoKind : uint8_t {UnifiedThin, UnifiedRegular, Default};
|
||||
|
||||
// For -z gcs=
|
||||
enum class GcsPolicy { Implicit, Never, Always };
|
||||
|
||||
struct SymbolVersion {
|
||||
llvm::StringRef name;
|
||||
bool isExternCpp;
|
||||
@@ -188,6 +191,7 @@ struct Config {
|
||||
StringRef zBtiReport = "none";
|
||||
StringRef zCetReport = "none";
|
||||
StringRef zPauthReport = "none";
|
||||
StringRef zGcsReport = "none";
|
||||
bool ltoBBAddrMap;
|
||||
llvm::StringRef ltoBasicBlockSections;
|
||||
std::pair<llvm::StringRef, llvm::StringRef> thinLTOObjectSuffixReplace;
|
||||
@@ -341,6 +345,7 @@ struct Config {
|
||||
UnresolvedPolicy unresolvedSymbols;
|
||||
UnresolvedPolicy unresolvedSymbolsInShlib;
|
||||
Target2Policy target2;
|
||||
GcsPolicy zGcs;
|
||||
bool power10Stubs;
|
||||
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
|
||||
BuildIdKind buildId = BuildIdKind::None;
|
||||
|
||||
@@ -466,6 +466,10 @@ static void checkOptions() {
|
||||
error("-z bti-report only supported on AArch64");
|
||||
if (config->zPauthReport != "none")
|
||||
error("-z pauth-report only supported on AArch64");
|
||||
if (config->zGcsReport != "none")
|
||||
error("-z gcs-report only supported on AArch64");
|
||||
if (config->zGcs != GcsPolicy::Implicit)
|
||||
error("-z gcs only supported on AArch64");
|
||||
}
|
||||
|
||||
if (config->emachine != EM_386 && config->emachine != EM_X86_64 &&
|
||||
@@ -560,6 +564,25 @@ static uint8_t getZStartStopVisibility(opt::InputArgList &args) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GcsPolicy getZGcs(opt::InputArgList &args) {
|
||||
GcsPolicy ret = GcsPolicy::Implicit;
|
||||
for (auto *arg : args.filtered(OPT_z)) {
|
||||
std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
|
||||
if (kv.first == "gcs") {
|
||||
arg->claim();
|
||||
if (kv.second == "implicit")
|
||||
ret = GcsPolicy::Implicit;
|
||||
else if (kv.second == "never")
|
||||
ret = GcsPolicy::Never;
|
||||
else if (kv.second == "always")
|
||||
ret = GcsPolicy::Always;
|
||||
else
|
||||
error("unknown -z gcs= value: " + kv.second);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Report a warning for an unknown -z option.
|
||||
static void checkZOptions(opt::InputArgList &args) {
|
||||
// This function is called before getTarget(), when certain options are not
|
||||
@@ -1438,6 +1461,7 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
config->zCopyreloc = getZFlag(args, "copyreloc", "nocopyreloc", true);
|
||||
config->zForceBti = hasZOption(args, "force-bti");
|
||||
config->zForceIbt = hasZOption(args, "force-ibt");
|
||||
config->zGcs = getZGcs(args);
|
||||
config->zGlobal = hasZOption(args, "global");
|
||||
config->zGnustack = getZGnuStack(args);
|
||||
config->zHazardplt = hasZOption(args, "hazardplt");
|
||||
@@ -1510,6 +1534,7 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
|
||||
auto reports = {std::make_pair("bti-report", &config->zBtiReport),
|
||||
std::make_pair("cet-report", &config->zCetReport),
|
||||
std::make_pair("gcs-report", &config->zGcsReport),
|
||||
std::make_pair("pauth-report", &config->zPauthReport)};
|
||||
for (opt::Arg *arg : args.filtered(OPT_z)) {
|
||||
std::pair<StringRef, StringRef> option =
|
||||
@@ -2677,6 +2702,11 @@ static void readSecurityNotes() {
|
||||
toString(f) + ": -z bti-report: file does not have "
|
||||
"GNU_PROPERTY_AARCH64_FEATURE_1_BTI property");
|
||||
|
||||
checkAndReportMissingFeature(
|
||||
config->zGcsReport, features, GNU_PROPERTY_AARCH64_FEATURE_1_GCS,
|
||||
toString(f) + ": -z gcs-report: file does not have "
|
||||
"GNU_PROPERTY_AARCH64_FEATURE_1_GCS property");
|
||||
|
||||
checkAndReportMissingFeature(
|
||||
config->zCetReport, features, GNU_PROPERTY_X86_FEATURE_1_IBT,
|
||||
toString(f) + ": -z cet-report: file does not have "
|
||||
@@ -2729,6 +2759,12 @@ static void readSecurityNotes() {
|
||||
// Force enable Shadow Stack.
|
||||
if (config->zShstk)
|
||||
config->andFeatures |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
|
||||
|
||||
// Force enable/disable GCS
|
||||
if (config->zGcs == GcsPolicy::Always)
|
||||
config->andFeatures |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
|
||||
else if (config->zGcs == GcsPolicy::Never)
|
||||
config->andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
|
||||
}
|
||||
|
||||
static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {
|
||||
|
||||
134
lld/test/ELF/aarch64-feature-gcs.s
Normal file
134
lld/test/ELF/aarch64-feature-gcs.s
Normal file
@@ -0,0 +1,134 @@
|
||||
# REQUIRES: aarch64
|
||||
# RUN: rm -rf %t && split-file %s %t && cd %t
|
||||
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func1-gcs.s -o func1-gcs.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2.s -o func2.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func2-gcs.s -o func2-gcs.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func3.s -o func3.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu func3-gcs.s -o func3-gcs.o
|
||||
|
||||
## GCS should be enabled when it's enabled in all inputs or when it's forced on.
|
||||
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o gcs
|
||||
# RUN: llvm-readelf -n gcs | FileCheck --check-prefix GCS %s
|
||||
# RUN: ld.lld func1-gcs.o func3-gcs.o --shared -o gcs.so
|
||||
# RUN: llvm-readelf -n gcs.so | FileCheck --check-prefix GCS %s
|
||||
# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o force-gcs -z gcs=always
|
||||
# RUN: llvm-readelf -n force-gcs | FileCheck --check-prefix GCS %s
|
||||
# RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs.so -z gcs=always
|
||||
# RUN: llvm-readelf -n force-gcs.so | FileCheck --check-prefix GCS %s
|
||||
# RUN: ld.lld func2-gcs.o func3.o --shared -o force-gcs2.so -z gcs=never -z gcs=always
|
||||
# RUN: llvm-readelf -n force-gcs2.so | FileCheck --check-prefix GCS %s
|
||||
|
||||
# GCS: Properties: aarch64 feature: GCS
|
||||
|
||||
## GCS should not be enabled if it's not enabled in at least one input.
|
||||
|
||||
# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o no-gcs
|
||||
# RUN: llvm-readelf -n no-gcs | count 0
|
||||
# RUN: ld.lld func2-gcs.o func3.o --shared -o no-gcs.so
|
||||
|
||||
## GCS should be disabled with gcs=never, even if GCS is present in all inputs.
|
||||
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=never -o never-gcs
|
||||
# RUN: llvm-readelf -n never-gcs | count 0
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=always -z gcs=never -o never-gcs2
|
||||
# RUN: llvm-readelf -n never-gcs2 | count 0
|
||||
|
||||
## gcs-report should report any input files that don't have the gcs property.
|
||||
|
||||
# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
|
||||
# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
|
||||
# RUN: ld.lld func1-gcs.o func2.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=never 2>&1 | FileCheck --check-prefix=REPORT-WARN %s
|
||||
# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
|
||||
# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
|
||||
# RUN: not ld.lld func2-gcs.o func3.o --shared -o /dev/null -z gcs-report=error -z gcs=never 2>&1 | FileCheck --check-prefix=REPORT-ERROR %s
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning 2>&1 | count 0
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=always 2>&1 | count 0
|
||||
# RUN: ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -o /dev/null -z gcs-report=warning -z gcs=never 2>&1 | count 0
|
||||
|
||||
# REPORT-WARN: warning: func2.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
|
||||
# REPORT-ERROR: error: func3.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
|
||||
|
||||
## An invalid gcs option should give an error
|
||||
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=nonsense 2>&1 | FileCheck --check-prefix=INVALID %s
|
||||
|
||||
# INVALID: error: unknown -z gcs= value: nonsense
|
||||
|
||||
#--- func1-gcs.s
|
||||
.section ".note.gnu.property", "a"
|
||||
.long 4
|
||||
.long 0x10
|
||||
.long 0x5
|
||||
.asciz "GNU"
|
||||
|
||||
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
|
||||
.long 4
|
||||
.long 4 // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
|
||||
.long 0
|
||||
|
||||
.text
|
||||
.globl _start
|
||||
.type func1,%function
|
||||
func1:
|
||||
bl func2
|
||||
ret
|
||||
|
||||
#--- func2.s
|
||||
|
||||
.text
|
||||
.globl func2
|
||||
.type func2,@function
|
||||
func2:
|
||||
.globl func3
|
||||
.type func3, @function
|
||||
bl func3
|
||||
ret
|
||||
|
||||
#--- func2-gcs.s
|
||||
|
||||
.section ".note.gnu.property", "a"
|
||||
.long 4
|
||||
.long 0x10
|
||||
.long 0x5
|
||||
.asciz "GNU"
|
||||
|
||||
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
|
||||
.long 4
|
||||
.long 4 // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
|
||||
.long 0
|
||||
|
||||
.text
|
||||
.globl func2
|
||||
.type func2,@function
|
||||
func2:
|
||||
.globl func3
|
||||
.type func3, @function
|
||||
bl func3
|
||||
ret
|
||||
|
||||
#--- func3.s
|
||||
|
||||
.text
|
||||
.globl func3
|
||||
.type func3,@function
|
||||
func3:
|
||||
ret
|
||||
|
||||
#--- func3-gcs.s
|
||||
|
||||
.section ".note.gnu.property", "a"
|
||||
.long 4
|
||||
.long 0x10
|
||||
.long 0x5
|
||||
.asciz "GNU"
|
||||
|
||||
.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND
|
||||
.long 4
|
||||
.long 4 // GNU_PROPERTY_AARCH64_FEATURE_1_GCS
|
||||
.long 0
|
||||
|
||||
.text
|
||||
.globl func3
|
||||
.type func3,@function
|
||||
func3:
|
||||
ret
|
||||
Reference in New Issue
Block a user