diff --git a/llvm/test/tools/llvm-objcopy/wasm/basic-keep.test b/llvm/test/tools/llvm-objcopy/wasm/basic-keep.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/basic-keep.test @@ -0,0 +1,42 @@ +## Test that --keep-section keeps a section when stripping. +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --strip-all --keep-section=foo %t %t2 +# RUN: obj2yaml %t2 | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: - Type: TYPE +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Payload: DEADBEEF +# CHECK-NOT: Section + +## Test that keep overrides an explicit removal. +# RUN: llvm-objcopy --remove-section=foo --keep-section=foo %t %t2 +# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=REMOVE + +# REMOVE: Sections: +# REMOVE: - Type: TYPE +# REMOVE: - Type: CUSTOM +# REMOVE: Name: producers +# REMOVE: - Type: CUSTOM +# REMOVE: Name: foo + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 + - Type: CUSTOM + Name: foo + Payload: DEADBEEF diff --git a/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test b/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test @@ -0,0 +1,28 @@ +## Test --only-section. +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --only-section=producers %t %t2 +# RUN: obj2yaml %t2 | FileCheck %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: +# CHECK-NOT: Section + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 diff --git a/llvm/test/tools/llvm-objcopy/wasm/basic-strip.test b/llvm/test/tools/llvm-objcopy/wasm/basic-strip.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/basic-strip.test @@ -0,0 +1,32 @@ +## Test that all custom sections are stripped with --strip-all. +# RUN: yaml2obj %s -o %t +# RUN: llvm-strip --strip-all %t +# RUN: obj2yaml %t | FileCheck %s + +## The default no-arg behavior is the same as --strip-all. +# RUN: llvm-strip %t +# RUN: obj2yaml %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: - Type: TYPE +# CHECK-NOT: Section + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 + - Type: CUSTOM + Name: foo + Payload: DEADBEEF diff --git a/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test @@ -0,0 +1,34 @@ +## 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 + +# CHECK: Sections: +# CHECK-NEXT: - Type: CUSTOM +# CHECK-NEXT: Name: .debug_info +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: .debug_line +# CHECK-NOT: Section + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Type: CUSTOM + Name: .debug_info + Payload: CAFE1234 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 + - Type: CUSTOM + Name: .debug_line + Payload: DEADBEEF diff --git a/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test @@ -0,0 +1,33 @@ +## Test that debug sections are stripped with --strip-debug +# RUN: yaml2obj %s -o %t +# RUN: llvm-strip --strip-debug %t +# RUN: obj2yaml %t | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: - Type: TYPE +# CHECK: - Type: CUSTOM +# CHECK-NEXT: Name: producers +# CHECK-NOT: Section + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Type: CUSTOM + Name: .debug_info + Payload: CAFE1234 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 + - Type: CUSTOM + Name: .debug_line + Payload: DEADBEEF diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp @@ -20,6 +20,11 @@ namespace wasm { using namespace object; +using SectionPred = std::function; + +static bool isDebugSection(const Section &Sec) { + return Sec.Name.startswith(".debug") || Sec.Name == "name"; +} static Error dumpSectionToFile(StringRef SecName, StringRef Filename, Object &Obj) { @@ -40,6 +45,62 @@ return createStringError(errc::invalid_argument, "section '%s' not found", SecName.str().c_str()); } + +static void removeSections(const CopyConfig &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) || Sec.SectionType == llvm::wasm::WASM_SEC_CUSTOM; + }; + } + + if (Config.OnlyKeepDebug) { + RemovePred = [](const Section &Sec) { + // Explictily keep debug sections regardless of previous removes. + if (isDebugSection(Sec)) + return false; + // Remove everything else, including known sections. + return true; + }; + } + + if (!Config.OnlySection.empty()) { + RemovePred = [&Config](const Section &Sec) { + // Explicitly keep these sections regardless of previous removes. + if (Config.OnlySection.matches(Sec.Name)) + return false; + // Remove everything else, inluding known sections. + return true; + }; + } + + 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 CopyConfig &Config, Object &Obj) { // Only support AddSection, DumpSection, RemoveSection for now. for (StringRef Flag : Config.DumpSection) { @@ -50,11 +111,7 @@ 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; @@ -79,8 +136,7 @@ !Config.SymbolsPrefix.empty() || !Config.AllocSectionsPrefix.empty() || Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility || !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() || - !Config.OnlySection.empty() || !Config.SymbolsToGlobalize.empty() || - !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || + !Config.SymbolsToGlobalize.empty() || !Config.SymbolsToLocalize.empty() || !Config.SymbolsToRemove.empty() || !Config.UnneededSymbolsToRemove.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || @@ -88,7 +144,7 @@ !Config.SetSectionFlags.empty() || !Config.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 Error::success(); }