1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[llvm-strip][WebAssembly] Support strip flags

Summary:
Add support for the basic section stripping (and keeping) flags for wasm:
strip with no flags, --strip-all, --strip-debug,
--only-section, --keep-section, and --only-keep-debug.

Factor section removal into a function and use a predicate chain like
the ELF implementation.

Reviewers: jhenderson, sbc100

Differential Revision: https://reviews.llvm.org/D73820
This commit is contained in:
Derek Schuff 2020-01-31 15:55:47 -08:00
parent a8da5bdd63
commit f708d3928c
9 changed files with 380 additions and 9 deletions

View File

@ -0,0 +1,26 @@
## Test that --keep-section keeps a debug section when stripping.
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --strip-all --keep-section=.debug_info %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not linking %s
# CHECK: Sections:
# CHECK: Name: .debug_info
# CHECK-NEXT: Payload: DEADBEEF
## Test that keep overrides an explicit removal.
# RUN: llvm-objcopy --remove-section=.debug_info --keep-section=.debug_info %t %t2
# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=KEEP
# KEEP: Sections:
# KEEP: Name: .debug_info
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: CUSTOM
Name: linking
Version: 2
- Type: CUSTOM
Name: .debug_info
Payload: DEADBEEF

View File

@ -0,0 +1,44 @@
## Test --only-section.
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --only-section=producers %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not linking %s
## Test that it's the same with only-section + keep-section (for the same section).
# RUN: llvm-objcopy --only-section=producers --keep-section=producers %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not linking %s
## Also test that only-section overrides remove-section.
# RUN: llvm-objcopy --only-section=producers --remove-section=producers %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not linking %s
## This file has both known and custom sections. Check that only the producers section is left.
# CHECK: Sections:
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: producers
# CHECK-NEXT: Tools:
## Test that only-section + keep-section keeps both sections.
# RUN: llvm-objcopy --only-section=producers --keep-section=linking %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=TYPE --check-prefix=KEEP %s
# KEEP: Name: linking
# KEEP: Name: producers
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes:
- I32
ReturnTypes:
- F32
- Type: CUSTOM
Name: linking
Version: 2
- Type: CUSTOM
Name: producers
Tools:
- Name: clang
Version: 9.0.0

View File

@ -0,0 +1,46 @@
## Test that debug, name, and producers sections are stripped with --strip-all.
## Other sections (unknown to LLVM, such as foo) are not stripped by --strip-all.
# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --strip-all %t
# RUN: obj2yaml %t | FileCheck --implicit-check-not producers --implicit-check-not .debug --implicit-check-not name %s
## The default no-arg behavior is the same as --strip-all.
# RUN: llvm-strip %t
# RUN: obj2yaml %t | FileCheck --implicit-check-not producers --implicit-check-not .debug --implicit-check-not name %s
# CHECK: Sections:
# CHECK-NEXT: - Type: TYPE
# CHECK: Name: foo
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes: []
ReturnTypes: []
- Type: FUNCTION
FunctionTypes: [ 0 ]
- Type: CODE
Functions:
- Index: 0
Locals: []
Body: 0B
- Type: CUSTOM
Name: name
FunctionNames:
- Index: 0
Name: foo
- Type: CUSTOM
Name: producers
Tools:
- Name: clang
Version: 9.0.0
- Type: CUSTOM
Name: .debug_info
Payload: DEADBEEF
- Type: CUSTOM
Name: foo
Payload: CAFE

View File

@ -0,0 +1,52 @@
## Test that only debug sections are kept with --only-keep-debug.
# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --only-keep-debug %t
# RUN: obj2yaml %t | FileCheck %s
## Test that keep-section overrides only-keep-debug.
# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --only-keep-debug --keep-section=foo %t
# RUN: obj2yaml %t | FileCheck --implicit-check-not=Name --check-prefix=CHECK --check-prefix=KEEP %s
# CHECK: Sections:
# CHECK: - Type: CUSTOM
# CHECK-NEXT: Name: .debug_info
# CHECK: - Type: CUSTOM
# CHECK-NEXT: Name: .debug_line
# KEEP: Name: foo
## Test that remove-section overrides only-keep-debug.
# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --only-keep-debug --remove-section=.debug_info %t
# RUN: obj2yaml %t | FileCheck %s --check-prefix=NOINFO --implicit-check-not=.debug_info
# NOINFO: Name: .debug_line
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes:
- I32
ReturnTypes:
- F32
- Type: CUSTOM
Name: .debug_info
Payload: CAFE1234
- Type: CUSTOM
Name: linking
Version: 2
- Type: CUSTOM
Name: producers
Tools:
- Name: clang
Version: 9.0.0
- Type: CUSTOM
Name: .debug_line
Payload: DEADBEEF
- Type: CUSTOM
Name: foo
Payload: CAFE

View File

@ -0,0 +1,34 @@
## Test that --strip-all removes debug, linking, and producers sections, but not
## known or unknown-custom sections.
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --strip-all %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=Type: %s
# CHECK: Sections:
# CHECK-NEXT: - Type: TYPE
# CHECK: - Type: CUSTOM
# CHECK-NEXT: Name: foo
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes: []
ReturnTypes: []
- Type: CUSTOM
Name: linking
Version: 2
- Type: CUSTOM
Name: producers
Tools:
- Name: clang
Version: 9.0.0
- Type: CUSTOM
Name: .debug_info
Payload: DEADBEEF
- Type: CUSTOM
Name: foo
Payload: CAFE

View File

@ -0,0 +1,53 @@
## Test that debug sections (but not linking or names) are stripped with --strip-debug
# RUN: yaml2obj %s -o %t
# RUN: llvm-strip --strip-debug %t
# RUN: obj2yaml %t | FileCheck --implicit-check-not=.debug %s
# CHECK: Sections:
# CHECK-NEXT: - Type: TYPE
# CHECK: Name: linking
# CHECK: Name: name
# CHECK-NEXT: FunctionNames:
# CHECK: Name: producers
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes: []
ReturnTypes: []
- Type: FUNCTION
FunctionTypes: [ 0 ]
- Type: CODE
Functions:
- Index: 0
Locals: []
Body: 0B
- Type: CUSTOM
Name: .debug_info
Payload: CAFE1234
- Type: CUSTOM
Name: linking
Version: 2
SymbolTable:
- Index: 0
Kind: FUNCTION
Name: foo
Flags: [ BINDING_LOCAL ]
Function: 0
- Type: CUSTOM
Name: name
FunctionNames:
- Index: 0
Name: foo
- Type: CUSTOM
Name: producers
Tools:
- Name: clang
Version: 9.0.0
- Type: CUSTOM
Name: .debug_line
Payload: DEADBEEF

View File

@ -0,0 +1,51 @@
## Test that linking, reloc, and name sections are stripped by --strip-all.
## These get a separate test because ObjectYaml understands relocs and names,
## so the test needs to be a valid object with relocs and names.
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --strip-all %t %t2
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=Type: %s
## Check that the known sections are still present.
# CHECK: Sections:
# CHECK: - Type: TYPE
# CHECK: - Type: FUNCTION
# CHECK: - Type: CODE
## Check that there are still functions in the code section.
# CHECK: Functions:
--- !WASM
FileHeader:
Version: 0x00000001
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes: []
ReturnTypes: []
- Type: FUNCTION
FunctionTypes: [ 0 ]
- Type: CODE
Relocations:
- Type: R_WASM_FUNCTION_INDEX_LEB
Index: 0
Offset: 0x4
Functions:
- Index: 0
Locals: []
Body: 1080808080000B
- Type: CUSTOM
Name: linking
Version: 2
SymbolTable:
- Index: 0
Kind: FUNCTION
Name: foo
Flags: [ BINDING_LOCAL ]
Function: 0
- Type: CUSTOM
Name: name
FunctionNames:
- Index: 0
Name: foo

View File

@ -614,16 +614,15 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
!Common.AllocSectionsPrefix.empty() ||
Common.DiscardMode != DiscardType::None || ELF.NewSymbolVisibility ||
!Common.SymbolsToAdd.empty() || !Common.RPathToAdd.empty() ||
!Common.OnlySection.empty() || !Common.SymbolsToGlobalize.empty() ||
!Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
!Common.SymbolsToRemove.empty() ||
!Common.SymbolsToGlobalize.empty() || !Common.SymbolsToLocalize.empty() ||
!Common.SymbolsToKeep.empty() || !Common.SymbolsToRemove.empty() ||
!Common.UnneededSymbolsToRemove.empty() ||
!Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
!Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty()) {
return createStringError(
llvm::errc::invalid_argument,
"only add-section, dump-section, and remove-section are supported");
"only flags for section dumping, removal, and addition are supported");
}
return Wasm;

View File

@ -19,6 +19,23 @@ namespace objcopy {
namespace wasm {
using namespace object;
using SectionPred = std::function<bool(const Section &Sec)>;
static bool isDebugSection(const Section &Sec) {
return Sec.Name.startswith(".debug");
}
static bool isLinkerSection(const Section &Sec) {
return Sec.Name.startswith("reloc.") || Sec.Name == "linking";
}
static bool isNameSection(const Section &Sec) { return Sec.Name == "name"; }
// Sections which are known to be "comments" or informational and do not affect
// program semantics.
static bool isCommentSection(const Section &Sec) {
return Sec.Name == "producers";
}
static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
Object &Obj) {
@ -39,6 +56,59 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
return createStringError(errc::invalid_argument, "section '%s' not found",
SecName.str().c_str());
}
static void removeSections(const CommonConfig &Config, Object &Obj) {
SectionPred RemovePred = [](const Section &) { return false; };
// Explicitly-requested sections.
if (!Config.ToRemove.empty()) {
RemovePred = [&Config](const Section &Sec) {
return Config.ToRemove.matches(Sec.Name);
};
}
if (Config.StripDebug) {
RemovePred = [RemovePred](const Section &Sec) {
return RemovePred(Sec) || isDebugSection(Sec);
};
}
if (Config.StripAll) {
RemovePred = [RemovePred](const Section &Sec) {
return RemovePred(Sec) || isDebugSection(Sec) || isLinkerSection(Sec) ||
isNameSection(Sec) || isCommentSection(Sec);
};
}
if (Config.OnlyKeepDebug) {
RemovePred = [&Config](const Section &Sec) {
// Keep debug sections, unless explicitly requested to remove.
// Remove everything else, including known sections.
return Config.ToRemove.matches(Sec.Name) || !isDebugSection(Sec);
};
}
if (!Config.OnlySection.empty()) {
RemovePred = [&Config](const Section &Sec) {
// Explicitly keep these sections regardless of previous removes.
// Remove everything else, inluding known sections.
return !Config.OnlySection.matches(Sec.Name);
};
}
if (!Config.KeepSection.empty()) {
RemovePred = [&Config, RemovePred](const Section &Sec) {
// Explicitly keep these sections regardless of previous removes.
if (Config.KeepSection.matches(Sec.Name))
return false;
// Otherwise defer to RemovePred.
return RemovePred(Sec);
};
}
Obj.removeSections(RemovePred);
}
static Error handleArgs(const CommonConfig &Config, Object &Obj) {
// Only support AddSection, DumpSection, RemoveSection for now.
for (StringRef Flag : Config.DumpSection) {
@ -49,11 +119,7 @@ static Error handleArgs(const CommonConfig &Config, Object &Obj) {
return createFileError(FileName, std::move(E));
}
Obj.removeSections([&Config](const Section &Sec) {
if (Config.ToRemove.matches(Sec.Name))
return true;
return false;
});
removeSections(Config, Obj);
for (StringRef Flag : Config.AddSection) {
StringRef SecName, FileName;