[lld] r356805 - [WebAssembly] Add linker options to control feature checking

Thomas Lively via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 22 13:43:06 PDT 2019


Author: tlively
Date: Fri Mar 22 13:43:06 2019
New Revision: 356805

URL: http://llvm.org/viewvc/llvm-project?rev=356805&view=rev
Log:
[WebAssembly] Add linker options to control feature checking

Summary:
Adds --check-features and --no-check-features. The default for now is
to enable the checking, but this might change in the future.

Also adds --features=foo,bar for precisely controlling the features
used in the output binary.

Depends on D59173.

Reviewers: sbc100, aheejin

Subscribers: dschuff, jgravelle-google, sunfish, jdoerfert, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59274

Added:
    lld/trunk/test/wasm/target-feature-none.yaml
Modified:
    lld/trunk/test/wasm/target-feature-disallowed.yaml
    lld/trunk/test/wasm/target-feature-required.yaml
    lld/trunk/test/wasm/target-feature-used.yaml
    lld/trunk/wasm/Config.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/Writer.cpp

Modified: lld/trunk/test/wasm/target-feature-disallowed.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/target-feature-disallowed.yaml?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/test/wasm/target-feature-disallowed.yaml (original)
+++ lld/trunk/test/wasm/target-feature-disallowed.yaml Fri Mar 22 13:43:06 2019
@@ -1,5 +1,9 @@
 # RUN: yaml2obj %s -o %t1.o
 
+# RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED
+
+# RUN: wasm-ld --no-entry --features=bar,baz,quux -o - %t1.o | obj2yaml | FileCheck %s --check-prefix UNSPECIFIED
+
 # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
 # RUN: wasm-ld --no-entry -o %t.disallowed.exe %t1.o %t.disallowed.o
 # RUN: obj2yaml < %t.disallowed.exe | FileCheck %s --check-prefix DISALLOWED
@@ -31,6 +35,28 @@ Sections:
         Name:          "bar"
 ...
 
+# SPECIFIED:        - Type:            CUSTOM
+# SPECIFIED-NEXT:     Name:            target_features
+# SPECIFIED-NEXT:     Features:
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            bar
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            baz
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            foo
+# SPECIFIED-NEXT: ...
+
+# UNSPECIFIED:        - Type:            CUSTOM
+# UNSPECIFIED-NEXT:     Name:            target_features
+# UNSPECIFIED-NEXT:     Features:
+# UNSPECIFIED-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NEXT:         Name:            bar
+# UNSPECIFIED-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NEXT:         Name:            baz
+# UNSPECIFIED-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NEXT:         Name:            quux
+# UNSPECIFIED-NEXT: ...
+
 # DISALLOWED:        - Type:            CUSTOM
 # DISALLOWED-NEXT:     Name:            target_features
 # DISALLOWED-NEXT:     Features:

Added: lld/trunk/test/wasm/target-feature-none.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/target-feature-none.yaml?rev=356805&view=auto
==============================================================================
--- lld/trunk/test/wasm/target-feature-none.yaml (added)
+++ lld/trunk/test/wasm/target-feature-none.yaml Fri Mar 22 13:43:06 2019
@@ -0,0 +1,33 @@
+# RUN: yaml2obj %s -o %t1.o
+
+# RUN: wasm-ld --no-entry -o - %t1.o | obj2yaml | FileCheck %s --check-prefix EMPTY
+
+# RUN: wasm-ld --no-entry --features= -o - %t1.o | obj2yaml | FileCheck %s --check-prefix EMPTY
+
+# RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED
+
+--- !WASM
+FileHeader:
+  Version:         0x00000001
+Sections:
+  - Type:            CUSTOM
+    Name:            linking
+    Version:         2
+  - Type:            CUSTOM
+    Name:            target_features
+    Features:        [ ]
+...
+
+# section is not emitted if it would be empty
+# EMPTY-NOT: target_features
+
+# SPECIFIED:        - Type:            CUSTOM
+# SPECIFIED-NEXT:     Name:            target_features
+# SPECIFIED-NEXT:     Features:
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            bar
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            baz
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            foo
+# SPECIFIED-NEXT: ...

Modified: lld/trunk/test/wasm/target-feature-required.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/target-feature-required.yaml?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/test/wasm/target-feature-required.yaml (original)
+++ lld/trunk/test/wasm/target-feature-required.yaml Fri Mar 22 13:43:06 2019
@@ -1,5 +1,11 @@
 # RUN: yaml2obj %s -o %t1.o
 
+# RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED
+
+# RUN: not wasm-ld --no-entry --features=bar,baz,quux -o - %t1.o 2>&1 | FileCheck %s --check-prefix UNSPECIFIED
+
+# RUN: wasm-ld --no-entry --no-check-features --features=bar,baz,quux -o - %t1.o | obj2yaml | FileCheck %s --check-prefix UNSPECIFIED-NOCHECK
+
 # RUN: yaml2obj %S/Inputs/require-feature-foo.yaml -o %t.required.o
 # RUN: wasm-ld --no-entry -o %t.required.exe %t1.o %t.required.o
 # RUN: obj2yaml < %t.required.exe | FileCheck %s --check-prefix REQUIRED
@@ -7,9 +13,13 @@
 # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
 # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED
 
+# RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED-NOCHECK
+
 # RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o
 # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.none.o 2>&1 | FileCheck %s --check-prefix NONE
 
+# RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.none.o | obj2yaml | FileCheck %s --check-prefix NONE-NOCHECK
+
 # Check that the following combinations of feature linkage policies
 # give the expected results:
 #
@@ -31,6 +41,30 @@ Sections:
         Name:          "foo"
 ...
 
+# SPECIFIED:        - Type:            CUSTOM
+# SPECIFIED-NEXT:     Name:            target_features
+# SPECIFIED-NEXT:     Features:
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            bar
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            baz
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            foo
+# SPECIFIED-NEXT: ...
+
+# UNSPECIFIED: Target feature 'foo' is not allowed.{{$}}
+
+# UNSPECIFIED-NOCHECK:        - Type:            CUSTOM
+# UNSPECIFIED-NOCHECK-NEXT:     Name:            target_features
+# UNSPECIFIED-NOCHECK-NEXT:     Features:
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            bar
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            baz
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            quux
+# UNSPECIFIED-NOCHECK-NEXT: ...
+
 # REQUIRED:        - Type:            CUSTOM
 # REQUIRED-NEXT:     Name:            target_features
 # REQUIRED-NEXT:     Features:
@@ -38,6 +72,20 @@ Sections:
 # REQUIRED-NEXT:         Name:            foo
 # REQUIRED-NEXT: ...
 
-# DISALLOWED: Target feature "foo" is disallowed
+# DISALLOWED: Target feature 'foo' is disallowed. Use --no-check-features to suppress.{{$}}
 
-# NONE: Missing required target feature "foo"
+# DISALLOWED-NOCHECK:        - Type:            CUSTOM
+# DISALLOWED-NOCHECK-NEXT:     Name:            target_features
+# DISALLOWED-NOCHECK-NEXT:     Features:
+# DISALLOWED-NOCHECK-NEXT:       - Prefix:          USED
+# DISALLOWED-NOCHECK-NEXT:         Name:            foo
+# DISALLOWED-NOCHECK-NEXT: ...
+
+# NONE: Missing required target feature 'foo'. Use --no-check-features to suppress.{{$}}
+
+# NONE-NOCHECK:        - Type:            CUSTOM
+# NONE-NOCHECK-NEXT:     Name:            target_features
+# NONE-NOCHECK-NEXT:     Features:
+# NONE-NOCHECK-NEXT:       - Prefix:          USED
+# NONE-NOCHECK-NEXT:         Name:            foo
+# NONE-NOCHECK-NEXT: ...

Modified: lld/trunk/test/wasm/target-feature-used.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/target-feature-used.yaml?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/test/wasm/target-feature-used.yaml (original)
+++ lld/trunk/test/wasm/target-feature-used.yaml Fri Mar 22 13:43:06 2019
@@ -1,5 +1,11 @@
 # RUN: yaml2obj %s -o %t1.o
 
+# RUN: wasm-ld --no-entry --features=foo,bar,baz -o - %t1.o | obj2yaml | FileCheck %s --check-prefix SPECIFIED
+
+# RUN: not wasm-ld --no-entry --features=bar,baz,quux -o - %t1.o 2>&1 | FileCheck %s --check-prefix UNSPECIFIED
+
+# RUN: wasm-ld --no-entry --no-check-features --features=bar,baz,quux -o - %t1.o | obj2yaml | FileCheck %s --check-prefix UNSPECIFIED-NOCHECK
+
 # RUN: yaml2obj %S/Inputs/use-feature-foo.yaml -o %t.used.o
 # RUN: wasm-ld --no-entry -o %t.used.exe %t1.o %t.used.o
 # RUN: obj2yaml < %t.used.exe | FileCheck %s --check-prefix USED
@@ -11,6 +17,8 @@
 # RUN: yaml2obj %S/Inputs/disallow-feature-foo.yaml -o %t.disallowed.o
 # RUN: not wasm-ld --no-entry -o /dev/null %t1.o %t.disallowed.o 2>&1 | FileCheck %s --check-prefix DISALLOWED
 
+# RUN: wasm-ld --no-entry --no-check-features -o - %t1.o %t.disallowed.o | obj2yaml | FileCheck %s --check-prefix DISALLOWED-NOCHECK
+
 # RUN: yaml2obj %S/Inputs/no-feature-foo.yaml -o %t.none.o
 # RUN: wasm-ld --no-entry -o %t.none.exe %t1.o %t.none.o
 # RUN: obj2yaml %t.none.exe | FileCheck %s --check-prefix NONE
@@ -37,6 +45,30 @@ Sections:
         Name:          "foo"
 ...
 
+# SPECIFIED:        - Type:            CUSTOM
+# SPECIFIED-NEXT:     Name:            target_features
+# SPECIFIED-NEXT:     Features:
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            bar
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            baz
+# SPECIFIED-NEXT:       - Prefix:          USED
+# SPECIFIED-NEXT:         Name:            foo
+# SPECIFIED-NEXT: ...
+
+# UNSPECIFIED: Target feature 'foo' is not allowed.{{$}}
+
+# UNSPECIFIED-NOCHECK:        - Type:            CUSTOM
+# UNSPECIFIED-NOCHECK-NEXT:     Name:            target_features
+# UNSPECIFIED-NOCHECK-NEXT:     Features:
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            bar
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            baz
+# UNSPECIFIED-NOCHECK-NEXT:       - Prefix:          USED
+# UNSPECIFIED-NOCHECK-NEXT:         Name:            quux
+# UNSPECIFIED-NOCHECK-NEXT: ...
+
 # USED:        - Type:            CUSTOM
 # USED-NEXT:     Name:            target_features
 # USED-NEXT:     Features:
@@ -51,7 +83,14 @@ Sections:
 # REQUIRED-NEXT:         Name:            foo
 # REQUIRED-NEXT: ...
 
-# DISALLOWED: Target feature "foo" is disallowed
+# DISALLOWED: Target feature 'foo' is disallowed. Use --no-check-features to suppress.{{$}}
+
+# DISALLOWED-NOCHECK:        - Type:            CUSTOM
+# DISALLOWED-NOCHECK-NEXT:     Name:            target_features
+# DISALLOWED-NOCHECK-NEXT:     Features:
+# DISALLOWED-NOCHECK-NEXT:       - Prefix:          USED
+# DISALLOWED-NOCHECK-NEXT:         Name:            foo
+# DISALLOWED-NOCHECK-NEXT: ...
 
 # NONE:        - Type:            CUSTOM
 # NONE-NEXT:     Name:            target_features

Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Fri Mar 22 13:43:06 2019
@@ -19,6 +19,7 @@ namespace wasm {
 
 struct Configuration {
   bool AllowUndefined;
+  bool CheckFeatures;
   bool CompressRelocations;
   bool Demangle;
   bool DisableVerify;
@@ -54,6 +55,7 @@ struct Configuration {
   llvm::StringSet<> AllowUndefinedSymbols;
   std::vector<llvm::StringRef> SearchPaths;
   llvm::CachePruningPolicy ThinLTOCachePolicy;
+  llvm::Optional<std::vector<std::string>> Features;
 
   // True if we are creating position-independent code.
   bool Pic;

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Fri Mar 22 13:43:06 2019
@@ -21,6 +21,7 @@
 #include "lld/Common/Version.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Object/Wasm.h"
+#include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Path.h"
@@ -292,6 +293,8 @@ static StringRef getEntry(opt::InputArgL
 // of these values.
 static void setConfigs(opt::InputArgList &Args) {
   Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
+  Config->CheckFeatures =
+      Args.hasFlag(OPT_check_features, OPT_no_check_features, true);
   Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);
   Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
   Config->DisableVerify = Args.hasArg(OPT_disable_verify);
@@ -339,6 +342,13 @@ static void setConfigs(opt::InputArgList
   Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);
   Config->ZStackSize =
       args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);
+
+  if (auto *Arg = Args.getLastArg(OPT_features)) {
+    Config->Features =
+        llvm::Optional<std::vector<std::string>>(std::vector<std::string>());
+    for (StringRef S : Arg->getValues())
+      Config->Features->push_back(S);
+  }
 }
 
 // Some command line options or some combinations of them are not allowed.

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Fri Mar 22 13:43:06 2019
@@ -155,6 +155,13 @@ defm whole_archive: B<"whole-archive",
     "Force load of all members in a static library",
     "Do not force load of all members in a static library (default)">;
 
+defm check_features: B<"check-features",
+    "Check feature compatibility of linked objects (default)",
+    "Ignore feature compatibility of linked objects">;
+
+def features: CommaJoined<["--", "-"], "features=">,
+  HelpText<"Comma-separated used features, inferred from input objects by default.">;
+
 // Aliases
 def: JoinedOrSeparate<["-"], "e">, Alias<entry>;
 def: J<"entry=">, Alias<entry>;

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=356805&r1=356804&r2=356805&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Fri Mar 22 13:43:06 2019
@@ -878,18 +878,30 @@ void Writer::createSections() {
 }
 
 void Writer::calculateTargetFeatures() {
+  SmallSet<std::string, 8> Used;
   SmallSet<std::string, 8> Required;
   SmallSet<std::string, 8> Disallowed;
 
+  // Only infer used features if user did not specify features
+  bool InferFeatures = !Config->Features.hasValue();
+
+  if (!InferFeatures) {
+    for (auto &Feature : Config->Features.getValue())
+      TargetFeatures.insert(Feature);
+    // No need to read or check features
+    if (!Config->CheckFeatures)
+      return;
+  }
+
   // Find the sets of used, required, and disallowed features
   for (ObjFile *File : Symtab->ObjectFiles) {
     for (auto &Feature : File->getWasmObj()->getTargetFeatures()) {
       switch (Feature.Prefix) {
       case WASM_FEATURE_PREFIX_USED:
-        TargetFeatures.insert(Feature.Name);
+        Used.insert(Feature.Name);
         break;
       case WASM_FEATURE_PREFIX_REQUIRED:
-        TargetFeatures.insert(Feature.Name);
+        Used.insert(Feature.Name);
         Required.insert(Feature.Name);
         break;
       case WASM_FEATURE_PREFIX_DISALLOWED:
@@ -902,6 +914,20 @@ void Writer::calculateTargetFeatures() {
     }
   }
 
+  if (InferFeatures)
+    TargetFeatures.insert(Used.begin(), Used.end());
+
+  if (!Config->CheckFeatures)
+    return;
+
+  // Validate that used features are allowed in output
+  if (!InferFeatures) {
+    for (auto &Feature : Used) {
+      if (!TargetFeatures.count(Feature))
+        error(Twine("Target feature '") + Feature + "' is not allowed.");
+    }
+  }
+
   // Validate the required and disallowed constraints for each file
   for (ObjFile *File : Symtab->ObjectFiles) {
     SmallSet<std::string, 8> ObjectFeatures;
@@ -910,11 +936,13 @@ void Writer::calculateTargetFeatures() {
         continue;
       ObjectFeatures.insert(Feature.Name);
       if (Disallowed.count(Feature.Name))
-        error("Target feature \"" + Feature.Name + "\" is disallowed");
+        error(Twine("Target feature '") + Feature.Name +
+              "' is disallowed. Use --no-check-features to suppress.");
     }
     for (auto &Feature : Required) {
       if (!ObjectFeatures.count(Feature))
-        error(Twine("Missing required target feature \"") + Feature + "\"");
+        error(Twine("Missing required target feature '") + Feature +
+              "'. Use --no-check-features to suppress.");
     }
   }
 }




More information about the llvm-commits mailing list