mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-05 00:48:08 +00:00
Reland "[WebAssembly] Add linker options to control feature checking"
Do not pipe binary data between processes in lit tests this time, since it turns out that can break on Windows. This reverts commit 84c8652fc3085155d0f9c355455e5a797c6d9db6. llvm-svn: 356975
This commit is contained in:
parent
2d000e395e
commit
82de51a3ae
@ -1,12 +1,18 @@
|
||||
# RUN: yaml2obj %s -o %t1.o
|
||||
|
||||
# RUN: wasm-ld --no-entry --features=foo,bar,baz -o %t.specified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.specified.wasm | FileCheck %s --check-prefix SPECIFIED
|
||||
|
||||
# RUN: wasm-ld --no-entry --features=bar,baz,quux -o %t.unspecified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.unspecified.wasm | 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
|
||||
# RUN: wasm-ld --no-entry -o %t.disallowed.wasm %t1.o %t.disallowed.o
|
||||
# RUN: obj2yaml %t.disallowed.wasm | FileCheck %s --check-prefix DISALLOWED
|
||||
|
||||
# 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
|
||||
# RUN: wasm-ld --no-entry -o %t.none.wasm %t1.o %t.none.o
|
||||
# RUN: obj2yaml %t.none.wasm | FileCheck %s --check-prefix NONE
|
||||
|
||||
# Check that the following combinations of feature linkage policies
|
||||
# give the expected results:
|
||||
@ -31,6 +37,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:
|
||||
|
36
lld/test/wasm/target-feature-none.yaml
Normal file
36
lld/test/wasm/target-feature-none.yaml
Normal file
@ -0,0 +1,36 @@
|
||||
# RUN: yaml2obj %s -o %t1.o
|
||||
|
||||
# RUN: wasm-ld --no-entry -o %t.empty.wasm %t1.o
|
||||
# RUN: obj2yaml %t.empty.wasm | FileCheck %s --check-prefix EMPTY
|
||||
|
||||
# RUN: wasm-ld --no-entry --features= -o %t.empty.2.wasm %t1.o
|
||||
# RUN: obj2yaml %t.empty.2.wasm | FileCheck %s --check-prefix EMPTY
|
||||
|
||||
# RUN: wasm-ld --no-entry --features=foo,bar,baz -o %t.specified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.specified.wasm | 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: ...
|
@ -1,15 +1,29 @@
|
||||
# RUN: yaml2obj %s -o %t1.o
|
||||
|
||||
# RUN: wasm-ld --no-entry --features=foo,bar,baz -o %t.specified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.specified.wasm | 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 %t.unspecified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.unspecified.wasm | 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
|
||||
# RUN: wasm-ld --no-entry -o %t.required.wasm %t1.o %t.required.o
|
||||
# RUN: obj2yaml %t.required.wasm | FileCheck %s --check-prefix REQUIRED
|
||||
|
||||
# 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 %t.disallowed.wasm %t1.o %t.disallowed.o
|
||||
# RUN: obj2yaml %t.disallowed.wasm | 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 %t.none.wasm %t1.o %t.none.o
|
||||
# RUN: obj2yaml %t.none.wasm | FileCheck %s --check-prefix NONE-NOCHECK
|
||||
|
||||
# Check that the following combinations of feature linkage policies
|
||||
# give the expected results:
|
||||
#
|
||||
@ -31,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: ...
|
||||
|
||||
# REQUIRED: - Type: CUSTOM
|
||||
# REQUIRED-NEXT: Name: target_features
|
||||
# REQUIRED-NEXT: Features:
|
||||
@ -38,6 +76,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: ...
|
||||
|
@ -1,19 +1,30 @@
|
||||
# RUN: yaml2obj %s -o %t1.o
|
||||
|
||||
# RUN: wasm-ld --no-entry --features=foo,bar,baz -o %t.specified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.specified.wasm | 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 %t.unspecified.wasm %t1.o
|
||||
# RUN: obj2yaml %t.unspecified.wasm| 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
|
||||
# RUN: wasm-ld --no-entry -o %t.used.wasm %t1.o %t.used.o
|
||||
# RUN: obj2yaml %t.used.wasm | FileCheck %s --check-prefix USED
|
||||
|
||||
# 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
|
||||
# RUN: wasm-ld --no-entry -o %t.required.wasm %t1.o %t.required.o
|
||||
# RUN: obj2yaml %t.required.wasm | FileCheck %s --check-prefix REQUIRED
|
||||
|
||||
# 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 %t.disallowed.wasm %t1.o %t.disallowed.o
|
||||
# RUN: obj2yaml %t.disallowed.wasm | 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
|
||||
# RUN: wasm-ld --no-entry -o %t.none.wasm %t1.o %t.none.o
|
||||
# RUN: obj2yaml %t.none.wasm | FileCheck %s --check-prefix NONE
|
||||
|
||||
# Check that the following combinations of feature linkage policies
|
||||
# give the expected results:
|
||||
@ -37,6 +48,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 +86,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
|
||||
|
@ -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;
|
||||
|
@ -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::InputArgList &Args, StringRef Default) {
|
||||
// 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 &Args) {
|
||||
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.
|
||||
|
@ -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>;
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user