Index: test/tools/llvm-objcopy/strip-multiple-files.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/strip-multiple-files.test @@ -0,0 +1,89 @@ +# RUN: yaml2obj %s > %t.o + +# llvm-strip on two files: +# RUN: cp %t.o %t.1.o +# RUN: cp %t.o %t.2.o +# RUN: llvm-strip --keep-symbol=foo %t.1.o %t.2.o + +# Stripped objects are different from original. +# RUN: not cmp %t.o %t.1.o +# RUN: not cmp %t.o %t.2.o + +# Stripped objects are identical to each other. +# RUN: cmp %t.1.o %t.2.o + +# Basic check that strip worked normally. +# RUN: llvm-readobj -symbols %t.1.o | FileCheck %s +# RUN: llvm-readobj -symbols %t.2.o | FileCheck %s + +# llvm-strip on three files: +# RUN: cp %t.o %t.1.o +# RUN: cp %t.o %t.2.o +# RUN: cp %t.o %t.3.o +# RUN: llvm-strip --keep-symbol=foo %t.1.o %t.2.o %t.3.o + +# Stripped objects are different from original. +# RUN: not cmp %t.o %t.1.o +# RUN: not cmp %t.o %t.2.o +# RUN: not cmp %t.o %t.3.o + +# Stripped objects are identical to each other. +# RUN: cmp %t.1.o %t.2.o +# RUN: cmp %t.1.o %t.3.o + +# Basic check that strip worked normally. +# RUN: llvm-readobj -symbols %t.1.o | FileCheck %s +# RUN: llvm-readobj -symbols %t.2.o | FileCheck %s +# RUN: llvm-readobj -symbols %t.3.o | FileCheck %s + +# -o cannot be used with multiple input files +# RUN: cp %t.o %t.1.o +# RUN: cp %t.o %t.2.o +# RUN: not llvm-strip --keep-symbol=foo -o %t.stripped.o %t.1.o %t.2.o 2>&1 \ +# RUN: | FileCheck %s --check-prefix=BAD-O-FLAG + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] +Symbols: + Local: + - Name: foo + Type: STT_FUNC + Section: .text + Value: 0x1234 + Size: 8 + - Name: bar + Type: STT_FUNC + Section: .text + Value: 0x5678 + Size: 8 + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo +# CHECK-NEXT: Value: 0x1234 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: Function +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# BAD-O-FLAG: Multiple input files cannot be used in combination with -o. Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -128,6 +128,7 @@ Optional NewFlags; }; +// Configuration for copying/stripping a single file. struct CopyConfig { // Main input/output options StringRef InputFilename; @@ -177,6 +178,13 @@ bool Weaken = false; }; +// Configuration for the overall invocation of this tool. When invoked as +// objcopy, will always contain exactly one CopyConfig. When invoked as strip, +// will contain one or more CopyConfigs. +struct DriverConfig { + std::vector CopyConfigs; +}; + using SectionPred = std::function; enum SectionFlag { @@ -818,7 +826,7 @@ // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. -static CopyConfig parseObjcopyOptions(ArrayRef ArgsArr) { +static DriverConfig parseObjcopyOptions(ArrayRef ArgsArr) { ObjcopyOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -918,13 +926,15 @@ Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates); - return Config; + DriverConfig DC; + DC.CopyConfigs.push_back(std::move(Config)); + return DC; } // ParseStripOptions returns the config and sets the input arguments. If a // help flag is set then ParseStripOptions will print the help messege and // exit. -static CopyConfig parseStripOptions(ArrayRef ArgsArr) { +static DriverConfig parseStripOptions(ArrayRef ArgsArr) { StripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; llvm::opt::InputArgList InputArgs = @@ -949,14 +959,10 @@ if (Positional.empty()) error("No input file specified"); - if (Positional.size() > 1) - error("Support for multiple input files is not implemented yet"); + if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output)) + error("Multiple input files cannot be used in combination with -o"); CopyConfig Config; - Config.InputFilename = Positional[0]; - Config.OutputFilename = - InputArgs.getLastArgValue(STRIP_output, Positional[0]); - Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all); @@ -974,16 +980,31 @@ Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates); - return Config; + DriverConfig DC; + if (Positional.size() == 1) { + Config.InputFilename = Positional[0]; + Config.OutputFilename = + InputArgs.getLastArgValue(STRIP_output, Positional[0]); + DC.CopyConfigs.push_back(std::move(Config)); + } else { + for (const char *Filename : Positional) { + Config.InputFilename = Filename; + Config.OutputFilename = Filename; + DC.CopyConfigs.push_back(Config); + } + } + + return DC; } int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - CopyConfig Config; + DriverConfig DriverConfig; if (sys::path::stem(ToolName).endswith_lower("strip")) - Config = parseStripOptions(makeArrayRef(argv + 1, argc)); + DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc)); else - Config = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); - executeElfObjcopy(Config); + DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc)); + for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs) + executeElfObjcopy(CopyConfig); }