Skip to content

Commit 79fd58d

Browse files
committed
[AArch64][GCS][LLD] Introduce -z gcs-report-dynamic option
When GCS was introduced to LLD, the gcs-report option allowed for a user to gain information relating to if their relocatable objects supported the feature. For an executable or shared-library to support GCS, all relocatable objects must declare that they support GCS. The gcs-report checks were only done on relocatable object files, however for a program to enable GCS, the executable and all shared libraries that it loads must enable GCS. gcs-report-dynamic enables checks to be performed on all shared objects loaded by LLD, and in cases where GCS is not supported, a warning or error will be emitted. It should be noted that only shared files directly passed to LLD are checked for GCS support. Files that are noted in the `DT_NEEDED` tags are assumed to have had their GCS support checked when they were created. The behaviour of the -zgcs-dynamic-report option matches that of GNU ld. The behaviour is as follows unless the user explicitly sets the value: * -zgcs-report=warning or -zgcs-report=error implies -zgcs-report-dynamic=warning. This approach avoids inheriting an error level if the user wishes to continue building a module without rebuilding all the shared libraries. The same approach was taken for the GNU ld linker, so behaviour is identical across the toolchains. This implementation matches the error message and command line interface used within the GNU ld Linker. See here: https://inbox.sourceware.org/binutils/[email protected]/ To enable the checking of the GNU GCS Attributes when linking together an application, LLD needs to be able to parse a Shared Files program headers. This will enable a new option, allowing the user to output diagnostic information relating to if there are shared files being used that do not support the GCS extension. To define if a shared file support GCS, the GNU GCS Attribute will be stored within the Program Header, so this is parsed and, if found, the `andFeatures` value updated to reflect the support level.
1 parent 84b665c commit 79fd58d

File tree

6 files changed

+186
-60
lines changed

6 files changed

+186
-60
lines changed

lld/ELF/Config.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ struct Config {
232232
ReportPolicy zCetReport = ReportPolicy::None;
233233
ReportPolicy zPauthReport = ReportPolicy::None;
234234
ReportPolicy zGcsReport = ReportPolicy::None;
235+
ReportPolicy zGcsReportDynamic = ReportPolicy::None;
235236
ReportPolicy zExecuteOnlyReport = ReportPolicy::None;
236237
bool ltoBBAddrMap;
237238
llvm::StringRef ltoBasicBlockSections;
@@ -749,6 +750,18 @@ uint64_t errCount(Ctx &ctx);
749750

750751
ELFSyncStream InternalErr(Ctx &ctx, const uint8_t *buf);
751752

753+
inline StringRef gcsReportPolicytoString(GcsReportPolicy value) {
754+
StringRef ret;
755+
if (value == GcsReportPolicy::Warning)
756+
ret = "warning";
757+
else if (value == GcsReportPolicy::Error)
758+
ret = "error";
759+
else
760+
ret = "none";
761+
762+
return ret;
763+
}
764+
752765
#define CHECK2(E, S) lld::check2((E), [&] { return toStr(ctx, S); })
753766

754767
inline DiagLevel toDiagLevel(ReportPolicy policy) {

lld/ELF/Driver.cpp

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@
5656
#include "llvm/Object/IRObjectFile.h"
5757
#include "llvm/Remarks/HotnessThresholdParser.h"
5858
#include "llvm/Support/CommandLine.h"
59-
#include "llvm/Support/SaveAndRestore.h"
6059
#include "llvm/Support/Compression.h"
6160
#include "llvm/Support/FileSystem.h"
6261
#include "llvm/Support/GlobPattern.h"
6362
#include "llvm/Support/LEB128.h"
6463
#include "llvm/Support/Parallel.h"
6564
#include "llvm/Support/Path.h"
65+
#include "llvm/Support/SaveAndRestore.h"
6666
#include "llvm/Support/TarWriter.h"
6767
#include "llvm/Support/TargetSelect.h"
6868
#include "llvm/Support/TimeProfiler.h"
@@ -402,6 +402,8 @@ static void checkOptions(Ctx &ctx) {
402402
ErrAlways(ctx) << "-z pauth-report only supported on AArch64";
403403
if (ctx.arg.zGcsReport != ReportPolicy::None)
404404
ErrAlways(ctx) << "-z gcs-report only supported on AArch64";
405+
if (ctx.arg.zGcsReportDynamic != ReportPolicy::None)
406+
ErrAlways(ctx) << "-z gcs-report-dynamic only supported on AArch64";
405407
if (ctx.arg.zGcs != GcsPolicy::Implicit)
406408
ErrAlways(ctx) << "-z gcs only supported on AArch64";
407409
}
@@ -574,25 +576,35 @@ static GcsPolicy getZGcs(Ctx &ctx, opt::InputArgList &args) {
574576
return ret;
575577
}
576578

577-
static ReportPolicy getZGcsReport(Ctx &ctx, opt::InputArgList &args) {
578-
ReportPolicy ret = ReportPolicy::None;
579+
static void getZGcsReport(Ctx &ctx, opt::InputArgList &args) {
580+
bool reportDynamicDefined = false;
579581

580582
for (auto *arg : args.filtered(OPT_z)) {
581583
std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
582-
if (kv.first == "gcs-report") {
584+
if ((kv.first == "gcs-report") || kv.first == "gcs-report-dynamic") {
583585
arg->claim();
584-
if (kv.second == "none")
585-
ret = ReportPolicy::None;
586-
else if (kv.second == "warning")
587-
ret = ReportPolicy::Warning;
588-
else if (kv.second == "error")
589-
ret = ReportPolicy::Error;
590-
else
591-
ErrAlways(ctx) << "unknown -z gcs-report= value: " << kv.second;
586+
ReportPolicy value = StringSwitch<ReportPolicy>(kv.second)
587+
.Case("none", ReportPolicy::None)
588+
.Case("warning", ReportPolicy::Warning)
589+
.Case("error", ReportPolicy::Error);
590+
591+
if (kv.first == "gcs-report")
592+
ctx.arg.zGcsReport = value;
593+
else if (kv.first == "gcs-report-dynamic") {
594+
ctx.arg.zGcsReportDynamic = value;
595+
reportDynamicDefined = true;
596+
}
592597
}
593598
}
594599

595-
return ret;
600+
// The behaviour of -zgnu-report-dynamic matches that of GNU ld. When
601+
// -zgcs-report is set to `warning` or `error`, -zgcs-report-dynamic will
602+
// inherit this value if there is no user set value. This detects shared
603+
// libraries without the GCS property but does not the shared-libraries to be
604+
// rebuilt for successful linking
605+
if (!reportDynamicDefined && ctx.arg.zGcsReport != ReportPolicy::None &&
606+
ctx.arg.zGcsReportDynamic == ReportPolicy::None)
607+
ctx.arg.zGcsReportDynamic = ReportPolicy::Warning;
596608
}
597609

598610
// Report a warning for an unknown -z option.
@@ -1569,7 +1581,10 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
15691581
ctx.arg.zForceBti = hasZOption(args, "force-bti");
15701582
ctx.arg.zForceIbt = hasZOption(args, "force-ibt");
15711583
ctx.arg.zGcs = getZGcs(ctx, args);
1572-
ctx.arg.zGcsReport = getZGcsReport(ctx, args);
1584+
// getZGcsReport assings the values for `ctx.arg.zGcsReport` and
1585+
// `ctx.arg.zGcsReportDynamic within the function. By doing this, it saves
1586+
// calling the function twice, as both values can be parsed at once.
1587+
getZGcsReport(ctx, args);
15731588
ctx.arg.zGlobal = hasZOption(args, "global");
15741589
ctx.arg.zGnustack = getZGnuStack(args);
15751590
ctx.arg.zHazardplt = hasZOption(args, "hazardplt");
@@ -1642,10 +1657,11 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
16421657
ErrAlways(ctx) << errPrefix << pat.takeError() << ": " << kv.first;
16431658
}
16441659

1645-
auto reports = {std::make_pair("bti-report", &ctx.arg.zBtiReport),
1646-
std::make_pair("cet-report", &ctx.arg.zCetReport),
1647-
std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
1648-
std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
1660+
auto reports = {
1661+
std::make_pair("bti-report", &ctx.arg.zBtiReport),
1662+
std::make_pair("cet-report", &ctx.arg.zCetReport),
1663+
std::make_pair("execute-only-report", &ctx.arg.zExecuteOnlyReport),
1664+
std::make_pair("pauth-report", &ctx.arg.zPauthReport)};
16491665
for (opt::Arg *arg : args.filtered(OPT_z)) {
16501666
std::pair<StringRef, StringRef> option =
16511667
StringRef(arg->getValue()).split('=');
@@ -2927,6 +2943,22 @@ static void readSecurityNotes(Ctx &ctx) {
29272943
ctx.arg.andFeatures |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
29282944
else if (ctx.arg.zGcs == GcsPolicy::Never)
29292945
ctx.arg.andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
2946+
2947+
// If we are utilising GCS at any stage, the sharedFiles should be checked to
2948+
// ensure they also support this feature. The gcs-report-dynamic option is
2949+
// used to indicate if the user wants information relating to this, and will
2950+
// be set depending on the user's input, or warning if gcs-report is set to
2951+
// either `warning` or `error`.
2952+
if (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
2953+
for (SharedFile *f : ctx.sharedFiles)
2954+
reportUnless(ctx.arg.zGcsReportDynamic,
2955+
f->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
2956+
<< f
2957+
<< ": GCS is required by -z gcs, but this shared library lacks the "
2958+
"necessary property note. The "
2959+
<< "dynamic loader might not enable GCS or refuse to load the "
2960+
"program unless all shared library "
2961+
<< "dependencies have the GCS marking.";
29302962
}
29312963

29322964
static void initSectionsAndLocalSyms(ELFFileBase *file, bool ignoreComdats) {

lld/ELF/InputFiles.cpp

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,60 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
918918
handleSectionGroup<ELFT>(this->sections, entries);
919919
}
920920

921+
template <typename ELFT>
922+
static void parseGnuPropertyNote(Ctx &ctx, uint32_t &featureAndType,
923+
ArrayRef<uint8_t> &desc, ELFFileBase *f,
924+
const uint8_t *base,
925+
ArrayRef<uint8_t> *data = nullptr) {
926+
auto err = [&](const uint8_t *place) -> ELFSyncStream {
927+
auto diag = Err(ctx);
928+
diag << f->getName() << ":(" << ".note.gnu.property+0x"
929+
<< Twine::utohexstr(place - base) << "): ";
930+
return diag;
931+
};
932+
933+
while (!desc.empty()) {
934+
const uint8_t *place = desc.data();
935+
if (desc.size() < 8)
936+
return void(err(place) << "program property is too short");
937+
uint32_t type = read32<ELFT::Endianness>(desc.data());
938+
uint32_t size = read32<ELFT::Endianness>(desc.data() + 4);
939+
desc = desc.slice(8);
940+
if (desc.size() < size)
941+
return void(err(place) << "program property is too short");
942+
943+
if (type == featureAndType) {
944+
// We found a FEATURE_1_AND field. There may be more than one of these
945+
// in a .note.gnu.property section, for a relocatable object we
946+
// accumulate the bits set.
947+
if (size < 4)
948+
return void(err(place) << "FEATURE_1_AND entry is too short");
949+
f->andFeatures |= read32<ELFT::Endianness>(desc.data());
950+
} else if (ctx.arg.emachine == EM_AARCH64 &&
951+
type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
952+
// If the file being parsed is a SharedFile, we cannot pass in
953+
// the data variable as there is no InputSection to collect the
954+
// data from. As such, these are ignored. They are needed either
955+
// when loading a shared library oject.
956+
ArrayRef<uint8_t> contents = data ? *data : desc;
957+
if (!f->aarch64PauthAbiCoreInfo.empty()) {
958+
return void(
959+
err(contents.data())
960+
<< "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
961+
"not supported");
962+
} else if (size != 16) {
963+
return void(err(contents.data())
964+
<< "GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry "
965+
"is invalid: expected 16 bytes, but got "
966+
<< size);
967+
}
968+
f->aarch64PauthAbiCoreInfo = desc;
969+
}
970+
971+
// Padding is present in the note descriptor, if necessary.
972+
desc = desc.slice(alignTo<(ELFT::Is64Bits ? 8 : 4)>(size));
973+
}
974+
}
921975
// Read the following info from the .note.gnu.property section and write it to
922976
// the corresponding fields in `ObjFile`:
923977
// - Feature flags (32 bits) representing x86 or AArch64 features for
@@ -955,42 +1009,8 @@ static void readGnuProperty(Ctx &ctx, const InputSection &sec,
9551009

9561010
// Read a body of a NOTE record, which consists of type-length-value fields.
9571011
ArrayRef<uint8_t> desc = note.getDesc(sec.addralign);
958-
while (!desc.empty()) {
959-
const uint8_t *place = desc.data();
960-
if (desc.size() < 8)
961-
return void(err(place) << "program property is too short");
962-
uint32_t type = read32<ELFT::Endianness>(desc.data());
963-
uint32_t size = read32<ELFT::Endianness>(desc.data() + 4);
964-
desc = desc.slice(8);
965-
if (desc.size() < size)
966-
return void(err(place) << "program property is too short");
967-
968-
if (type == featureAndType) {
969-
// We found a FEATURE_1_AND field. There may be more than one of these
970-
// in a .note.gnu.property section, for a relocatable object we
971-
// accumulate the bits set.
972-
if (size < 4)
973-
return void(err(place) << "FEATURE_1_AND entry is too short");
974-
f.andFeatures |= read32<ELFT::Endianness>(desc.data());
975-
} else if (ctx.arg.emachine == EM_AARCH64 &&
976-
type == GNU_PROPERTY_AARCH64_FEATURE_PAUTH) {
977-
if (!f.aarch64PauthAbiCoreInfo.empty()) {
978-
return void(
979-
err(data.data())
980-
<< "multiple GNU_PROPERTY_AARCH64_FEATURE_PAUTH entries are "
981-
"not supported");
982-
} else if (size != 16) {
983-
return void(err(data.data())
984-
<< "GNU_PROPERTY_AARCH64_FEATURE_PAUTH entry "
985-
"is invalid: expected 16 bytes, but got "
986-
<< size);
987-
}
988-
f.aarch64PauthAbiCoreInfo = desc;
989-
}
990-
991-
// Padding is present in the note descriptor, if necessary.
992-
desc = desc.slice(alignTo<(ELFT::Is64Bits ? 8 : 4)>(size));
993-
}
1012+
const uint8_t *base = sec.content().data();
1013+
parseGnuPropertyNote<ELFT>(ctx, featureAndType, desc, &f, base, &data);
9941014

9951015
// Go to next NOTE record to look for more FEATURE_1_AND descriptions.
9961016
data = data.slice(nhdr->getSize(sec.addralign));
@@ -1418,6 +1438,37 @@ std::vector<uint32_t> SharedFile::parseVerneed(const ELFFile<ELFT> &obj,
14181438
return verneeds;
14191439
}
14201440

1441+
// To determine if a shared file can support any of the GNU Attributes,
1442+
// the .note.gnu.properties section need to be read. The appropriate
1443+
// location in memory is located then the GnuPropertyNote can be parsed.
1444+
// This is the same process as is used for readGnuProperty, however we
1445+
// do not pass the data variable as, without an InputSection, its value
1446+
// is unknown in a SharedFile. This is ok as the information that would
1447+
// be collected from this is irrelevant for a dynamic object.
1448+
template <typename ELFT>
1449+
void SharedFile::parseGnuAndFeatures(const uint8_t *base,
1450+
const typename ELFT::PhdrRange headers) {
1451+
if (headers.size() == 0)
1452+
return;
1453+
uint32_t featureAndType = ctx.arg.emachine == EM_AARCH64
1454+
? GNU_PROPERTY_AARCH64_FEATURE_1_AND
1455+
: GNU_PROPERTY_X86_FEATURE_1_AND;
1456+
1457+
for (unsigned i = 0; i < headers.size(); i++) {
1458+
if (headers[i].p_type != PT_GNU_PROPERTY)
1459+
continue;
1460+
const typename ELFT::Note note(
1461+
*reinterpret_cast<const typename ELFT::Nhdr *>(base +
1462+
headers[i].p_offset));
1463+
if (note.getType() != NT_GNU_PROPERTY_TYPE_0 || note.getName() != "GNU")
1464+
continue;
1465+
1466+
// Read a body of a NOTE record, which consists of type-length-value fields.
1467+
ArrayRef<uint8_t> desc = note.getDesc(headers[i].p_align);
1468+
parseGnuPropertyNote<ELFT>(ctx, featureAndType, desc, this, base);
1469+
}
1470+
}
1471+
14211472
// We do not usually care about alignments of data in shared object
14221473
// files because the loader takes care of it. However, if we promote a
14231474
// DSO symbol to point to .bss due to copy relocation, we need to keep
@@ -1454,10 +1505,12 @@ template <class ELFT> void SharedFile::parse() {
14541505
using Elf_Sym = typename ELFT::Sym;
14551506
using Elf_Verdef = typename ELFT::Verdef;
14561507
using Elf_Versym = typename ELFT::Versym;
1508+
using Elf_Phdr = typename ELFT::Phdr;
14571509

14581510
ArrayRef<Elf_Dyn> dynamicTags;
14591511
const ELFFile<ELFT> obj = this->getObj<ELFT>();
14601512
ArrayRef<Elf_Shdr> sections = getELFShdrs<ELFT>();
1513+
ArrayRef<Elf_Phdr> pHeaders = CHECK2(obj.program_headers(), this);
14611514

14621515
const Elf_Shdr *versymSec = nullptr;
14631516
const Elf_Shdr *verdefSec = nullptr;
@@ -1528,6 +1581,7 @@ template <class ELFT> void SharedFile::parse() {
15281581

15291582
verdefs = parseVerdefs<ELFT>(obj.base(), verdefSec);
15301583
std::vector<uint32_t> verneeds = parseVerneed<ELFT>(obj, verneedSec);
1584+
parseGnuAndFeatures<ELFT>(obj.base(), pHeaders);
15311585

15321586
// Parse ".gnu.version" section which is a parallel array for the symbol
15331587
// table. If a given file doesn't have a ".gnu.version" section, we use

lld/ELF/InputFiles.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ class SharedFile : public ELFFileBase {
364364
template <typename ELFT>
365365
std::vector<uint32_t> parseVerneed(const llvm::object::ELFFile<ELFT> &obj,
366366
const typename ELFT::Shdr *sec);
367+
template <typename ELFT>
368+
void parseGnuAndFeatures(const uint8_t *base,
369+
const typename ELFT::PhdrRange headers);
367370
};
368371

369372
class BinaryFile : public InputFile {

lld/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ Non-comprehensive list of changes in this release
2525

2626
ELF Improvements
2727
----------------
28+
* For AArch64, support for the ``-zgcs-report-dynamic`` option has been added. This will provide users with
29+
the ability to check any Dynamic Objects explicitly passed to LLD for the GNU GCS Attribute Flag. This is
30+
required for all files when linking with GCS enabled. Unless defined by the user, ``-zgcs-report-dynamic``
31+
inherits its value from the ``-zgcs-report`` option, capped at the ``warning`` level to ensure that a users
32+
module can still compile. This behaviour is designed to match the GNU ld Linker.
2833

2934
Breaking changes
3035
----------------

lld/test/ELF/aarch64-feature-gcs.s

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,34 @@
4949
# REPORT-WARN: warning: func2.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
5050
# REPORT-ERROR: error: func3.o: -z gcs-report: file does not have GNU_PROPERTY_AARCH64_FEATURE_1_GCS property
5151

52-
## An invalid gcs option should give an error
53-
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=nonsense 2>&1 | FileCheck --check-prefix=INVALID %s
54-
55-
# INVALID: error: unknown -z gcs= value: nonsense
52+
## gcs-report-dynamic should report any dynamic objects that does not have the gcs property. This also ensures the inhertance from gcs-report is working correctly.
53+
54+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
55+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report-dynamic=warning -z gcs-report=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
56+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
57+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report=error -z gcs-report-dynamic=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
58+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report-dynamic=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
59+
# RUN: ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report=error -z gcs-report-dynamic=warning -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-WARN-DYNAMIC %s
60+
# RUN: not ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report-dynamic=error -z gcs-report=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
61+
# RUN: not ld.lld func1-gcs.o func3-gcs.o no-gcs.so force-gcs.so -z gcs-report-dynamic=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
62+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report-dynamic=error -z gcs-report=error -z gcs=always 2>&1 | count 0
63+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report-dynamic=warning -z gcs-report=error -z gcs=always 2>&1 | count 0
64+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report=warning -z gcs=always 2>&1 | count 0
65+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report=error -z gcs=always 2>&1 | count 0
66+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report-dynamic=warning -z gcs=always 2>&1 | count 0
67+
# RUN: ld.lld func1-gcs.o func3-gcs.o force-gcs.so -z gcs-report-dynamic=error -z gcs=always 2>&1 | count 0
68+
69+
# REPORT-WARN-DYNAMIC: warning: no-gcs.so: GCS is required by -z gcs, but this shared library lacks the necessary property note. The dynamic loader might not enable GCS or refuse to load the program unless all shared library dependencies have the GCS marking.
70+
# REPORT-WARN-DYNAMIC-NOT: warning: force-gcs.so: GCS is required by -z gcs, but this shared library lacks the necessary property note. The dynamic loader might not enable GCS or refuse to load the program unless all shared library dependencies have the GCS marking.
71+
# REPORT-ERROR-DYNAMIC: error: no-gcs.so: GCS is required by -z gcs, but this shared library lacks the necessary property note. The dynamic loader might not enable GCS or refuse to load the program unless all shared library dependencies have the GCS marking.
72+
# REPORT-ERROR-DYNAMIC-NOT: error: force-gcs.so: GCS is required by -z gcs, but this shared library lacks the necessary property note. The dynamic loader might not enable GCS or refuse to load the program unless all shared library dependencies have the GCS marking.
5673

5774
## An invalid gcs option should give an error
58-
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs-report=nonsense 2>&1 | FileCheck --check-prefix=INVALID-GCS-REPORT %s
75+
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=nonsense -z gcs-report=nonsense -z gcs-report-dynamic=nonsense 2>&1 | FileCheck --check-prefix=INVALID %s
5976

60-
# INVALID-GCS-REPORT: error: unknown -z gcs-report= value: nonsense
77+
# INVALID: error: unknown -z gcs= value: nonsense
78+
# INVALID: error: unknown -z gcs-report= value: nonsense
79+
# INVALID: error: unknown -z gcs-report-dynamic= value: nonsense
6180

6281
#--- func1-gcs.s
6382
.section ".note.gnu.property", "a"

0 commit comments

Comments
 (0)