Skip to content

Commit b3564cb

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]/
1 parent fe9e621 commit b3564cb

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

lld/ELF/Config.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ enum LtoKind : uint8_t {UnifiedThin, UnifiedRegular, Default};
136136
// For -z gcs=
137137
enum class GcsPolicy { Implicit, Never, Always };
138138

139-
// For -z gcs-report=
139+
// For -z gcs-report= and -zgcs-report-dynamic
140140
enum class GcsReportPolicy { None, Warning, Error };
141141

142142
struct SymbolVersion {
@@ -397,6 +397,7 @@ struct Config {
397397
Target2Policy target2;
398398
GcsPolicy zGcs;
399399
GcsReportPolicy zGcsReport;
400+
GcsReportPolicy zGcsReportDynamic;
400401
bool power10Stubs;
401402
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
402403
BuildIdKind buildId = BuildIdKind::None;

lld/ELF/Driver.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,15 @@
4949
#include "llvm/ADT/STLExtras.h"
5050
#include "llvm/ADT/SetVector.h"
5151
#include "llvm/ADT/StringExtras.h"
52+
#include "llvm/ADT/StringRef.h"
5253
#include "llvm/ADT/StringSwitch.h"
54+
#include "llvm/BinaryFormat/ELF.h"
5355
#include "llvm/Config/llvm-config.h"
5456
#include "llvm/LTO/LTO.h"
5557
#include "llvm/Object/Archive.h"
58+
#include "llvm/Object/ELFTypes.h"
5659
#include "llvm/Object/IRObjectFile.h"
60+
#include "llvm/Option/ArgList.h"
5761
#include "llvm/Remarks/HotnessThresholdParser.h"
5862
#include "llvm/Support/CommandLine.h"
5963
#include "llvm/Support/SaveAndRestore.h"
@@ -68,6 +72,7 @@
6872
#include "llvm/Support/TimeProfiler.h"
6973
#include "llvm/Support/raw_ostream.h"
7074
#include <cstdlib>
75+
#include <memory>
7176
#include <tuple>
7277
#include <utility>
7378

@@ -402,6 +407,8 @@ static void checkOptions(Ctx &ctx) {
402407
ErrAlways(ctx) << "-z pauth-report only supported on AArch64";
403408
if (ctx.arg.zGcsReport != GcsReportPolicy::None)
404409
ErrAlways(ctx) << "-z gcs-report only supported on AArch64";
410+
if(ctx.arg.zGcsReportDynamic != GcsReportPolicy::None)
411+
ErrAlways(ctx) << "-z gcs-report-dynamic only supported on AArch64";
405412
if (ctx.arg.zGcs != GcsPolicy::Implicit)
406413
ErrAlways(ctx) << "-z gcs only supported on AArch64";
407414
}
@@ -595,6 +602,36 @@ static GcsReportPolicy getZGcsReport(Ctx &ctx, opt::InputArgList &args) {
595602
return ret;
596603
}
597604

605+
static GcsReportPolicy getZGcsReportDynamic(Ctx &ctx, opt::InputArgList &args) {
606+
GcsReportPolicy ret = GcsReportPolicy::None;
607+
for (auto *arg : args.filtered(OPT_z)) {
608+
std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
609+
if (kv.first == "gcs-report-dynamic") {
610+
arg->claim();
611+
if (kv.second == "none")
612+
ret = GcsReportPolicy::None;
613+
else if (kv.second == "warning")
614+
ret = GcsReportPolicy::Warning;
615+
else if (kv.second == "error")
616+
ret = GcsReportPolicy::Error;
617+
else
618+
ErrAlways(ctx) << "unknown -z gcs-report-dynamic= value: " << kv.second;
619+
// once the gcs-report-dynamic option has been processed, we want to break
620+
// from the loop to ensure we do not overwrite the return value if the
621+
// user has also passed a value for the gcs-report option.
622+
break;
623+
}
624+
// If the user has not defined a value for gcs-report-dynamic, but has for
625+
// gcs-report, we want to inherit that value for gcs-report-dynamic. This is
626+
// capped at a warning to ensure a users module can still build, while providing
627+
// information relating to if a dynamic object supports GCS.
628+
if (kv.first == "gcs-report" && (kv.second == "warning" || kv.second == "error"))
629+
ret = GcsReportPolicy::Warning;
630+
}
631+
632+
return ret;
633+
}
634+
598635
// Report a warning for an unknown -z option.
599636
static void checkZOptions(Ctx &ctx, opt::InputArgList &args) {
600637
// This function is called before getTarget(), when certain options are not
@@ -1575,6 +1612,7 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
15751612
ctx.arg.zForceIbt = hasZOption(args, "force-ibt");
15761613
ctx.arg.zGcs = getZGcs(ctx, args);
15771614
ctx.arg.zGcsReport = getZGcsReport(ctx, args);
1615+
ctx.arg.zGcsReportDynamic = getZGcsReportDynamic(ctx, args);
15781616
ctx.arg.zGlobal = hasZOption(args, "global");
15791617
ctx.arg.zGnustack = getZGnuStack(args);
15801618
ctx.arg.zHazardplt = hasZOption(args, "hazardplt");
@@ -2941,6 +2979,16 @@ static void readSecurityNotes(Ctx &ctx) {
29412979
ctx.arg.andFeatures |= GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
29422980
else if (ctx.arg.zGcs == GcsPolicy::Never)
29432981
ctx.arg.andFeatures &= ~GNU_PROPERTY_AARCH64_FEATURE_1_GCS;
2982+
2983+
// If we are utilising GCS at any stage, the sharedFiles should be checked to ensure they also support this feature.
2984+
// The gcs-report-dynamic option is used to indicate if the user wants information relating to this, and will be set
2985+
// depending on the user's input, or warning if gcs-report is set to either `warning` or `error`.
2986+
if(ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS)
2987+
for (SharedFile *f : ctx.sharedFiles)
2988+
reportGcsPolicy(ctx.arg.zGcsReportDynamic, f->andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_GCS) << f
2989+
<< ": GCS is required by -z gcs, but this shared library lacks the necessary property note. The "
2990+
<< "dynamic loader might not enable GCS or refuse to load the program unless all shared library "
2991+
<< "dependancies have the GCS marking.";
29442992
}
29452993

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

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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@
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+
## 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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -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 -o /dev/null -z gcs-report-dynamic=error -z gcs=always 2>&1 | FileCheck --check-prefix=REPORT-ERROR-DYNAMIC %s
62+
63+
# 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 dependancies have the GCS marking.
64+
# 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 dependancies have the GCS marking.
65+
# 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 dependancies have the GCS marking.
66+
# 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 dependancies have the GCS marking.
67+
5268
## An invalid gcs option should give an error
5369
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs=nonsense 2>&1 | FileCheck --check-prefix=INVALID %s
5470

@@ -59,6 +75,11 @@
5975

6076
# INVALID-GCS-REPORT: error: unknown -z gcs-report= value: nonsense
6177

78+
## An invalid gcs-report-dynamic option should give an error
79+
# RUN: not ld.lld func1-gcs.o func2-gcs.o func3-gcs.o -z gcs-report-dynamic=nonsense 2>&1 | FileCheck --check-prefix=INVALID-GCS-REPORT-DYNAMIC %s
80+
81+
# INVALID-GCS-REPORT-DYNAMIC: error: unknown -z gcs-report-dynamic= value: nonsense
82+
6283
#--- func1-gcs.s
6384
.section ".note.gnu.property", "a"
6485
.long 4

0 commit comments

Comments
 (0)