diff --git a/llvm/test/tools/llvm-objcopy/wasm/add-section.test b/llvm/test/tools/llvm-objcopy/wasm/add-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/add-section.test @@ -0,0 +1,73 @@ +## Test --add-section. This test dumps the section first and checks that adding +# it back doesn't change the result. +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --dump-section=producers=%t.sec %t +# RUN: llvm-objcopy --add-section=producers=%t.sec %t2 %t3 +# RUN: obj2yaml %t3 | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ParamTypes: + - I32 + ReturnTypes: + - F32 + - Index: 1 + ParamTypes: + - I32 + - I64 + ReturnTypes: [] + - Type: FUNCTION + FunctionTypes: + - 0 + - 1 + - Type: CODE + Relocations: + - Type: R_WASM_TABLE_INDEX_SLEB + Index: 0 + Offset: 0x00000000 + - Type: R_WASM_FUNCTION_INDEX_LEB + Index: 1 + Offset: 0x0000000 + Functions: + - Index: 0 + Locals: + - Type: I32 + Count: 3 + Body: 010101010B + - Index: 1 + Locals: + - Type: I32 + Count: 1 + Body: 010101010B + - Type: CUSTOM + Name: linking + Version: 2 + SymbolTable: + - Index: 0 + Kind: FUNCTION + Name: func1 + Flags: [ ] + Function: 0 + - Index: 1 + Kind: FUNCTION + Name: func2 + Flags: [ ] + Function: 1 + - Type: CUSTOM + Name: producers + Tools: + - Name: clang + Version: 9.0.0 + +... + +## Check that the producers section has been added back unchanged. +# CHECK: Name: producers +# CHECK-NEXT: Tools: +# CHECK-NEXT: - Name: clang +# CHECK-NEXT: Version: 9.0.0 diff --git a/llvm/test/tools/llvm-objcopy/wasm/dump-section.test b/llvm/test/tools/llvm-objcopy/wasm/dump-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/dump-section.test @@ -0,0 +1,26 @@ +## Test the contents of a custom section dumped from a binary. +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy --dump-section=producers=%t.sec %t +# RUN: od -t x1 %t.sec | FileCheck %s + +--- !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 +... + +## The contents of the producers section +# CHECK: 0000000 01 0c 70 72 6f 63 65 73 73 65 64 2d 62 79 01 05 +# CHECK: 0000020 63 6c 61 6e 67 05 39 2e 30 2e 30 diff --git a/llvm/test/tools/llvm-objcopy/wasm/remove-section.test b/llvm/test/tools/llvm-objcopy/wasm/remove-section.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/wasm/remove-section.test @@ -0,0 +1,25 @@ +## Test the --remove-section flag +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy -R producers %t %t2 +# RUN: obj2yaml %t2 | FileCheck %s + +--- !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 +... +## Check that the producers section has been removed, but not the type section. +# CHECK: TYPE +# CHECK-NOT: producers diff --git a/llvm/tools/llvm-objcopy/wasm/Object.h b/llvm/tools/llvm-objcopy/wasm/Object.h --- a/llvm/tools/llvm-objcopy/wasm/Object.h +++ b/llvm/tools/llvm-objcopy/wasm/Object.h @@ -57,6 +57,7 @@ // TODO: Support symbols, relocations, debug info, etc ArrayRef
getSections() { return Sections; }; void addSections(ArrayRef
NewSections); + void removeSections(function_ref ToRemove); private: // For now don't discriminate between kinds of sections. diff --git a/llvm/tools/llvm-objcopy/wasm/Object.cpp b/llvm/tools/llvm-objcopy/wasm/Object.cpp --- a/llvm/tools/llvm-objcopy/wasm/Object.cpp +++ b/llvm/tools/llvm-objcopy/wasm/Object.cpp @@ -24,6 +24,13 @@ } } +void Object::removeSections(function_ref ToRemove) { + // TODO: remove reloc sections for the removed section, handle symbols, etc + Sections.erase( + std::remove_if(std::begin(Sections), std::end(Sections), ToRemove), + std::end(Sections)); +} + } // end namespace wasm } // end namespace objcopy } // end namespace llvm 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 @@ -22,7 +22,65 @@ using namespace object; using namespace wasm; +// Adds named custom section with given contents to the object. +static void addSection(Object &Obj, StringRef Name, + ArrayRef Contents) { + Section Sec; + Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM; + Sec.Name = Name; + Sec.setOwnedContents(Contents); + Obj.addSections(Sec); +} + +static Error dumpSectionToFile(StringRef SecName, StringRef Filename, + Object &Obj) { + for (auto &Sec : Obj.getSections()) { + if (Sec.Name == SecName) { + ArrayRef Contents = Sec.getContents(); + Expected> BufferOrErr = + FileOutputBuffer::create(Filename, Contents.size()); + if (!BufferOrErr) + return BufferOrErr.takeError(); + std::unique_ptr Buf = std::move(*BufferOrErr); + std::copy(Contents.begin(), Contents.end(), Buf->getBufferStart()); + if (Error E = Buf->commit()) + return E; + return Error::success(); + } + } + return createStringError(errc::invalid_argument, "section '%s' not found", + SecName.str().c_str()); +} static Error handleArgs(const CopyConfig &Config, Object &Obj) { + // Only support AddSection, DumpSection, RemoveSection. + // Don't support OnlySection yet because we only operate on custom sections. + Obj.removeSections([&Config](const Section &Sec) { + if (Config.ToRemove.matches(Sec.Name)) + return true; + return false; + }); + + for (const auto &Flag : Config.AddSection) { + StringRef SecName, FileName; + std::tie(SecName, FileName) = Flag.split("="); + auto BufOrErr = MemoryBuffer::getFile(FileName); + if (!BufOrErr) + return createFileError(FileName, errorCodeToError(BufOrErr.getError())); + auto Buf = std::move(*BufOrErr); + addSection( + Obj, SecName, + makeArrayRef(reinterpret_cast(Buf->getBufferStart()), + Buf->getBufferSize())); + } + + for (const auto &Flag : Config.DumpSection) { + StringRef SecName; + StringRef FileName; + std::tie(SecName, FileName) = Flag.split("="); + if (Error E = dumpSectionToFile(SecName, FileName, Obj)) + return E; + } + if (!Config.AddGnuDebugLink.empty() || !Config.BuildIdLinkDir.empty() || Config.BuildIdLinkInput || Config.BuildIdLinkOutput || Config.ExtractPartition || !Config.SplitDWO.empty() || @@ -35,12 +93,10 @@ !Config.UnneededSymbolsToRemove.empty() || !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || - !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() || - !Config.ToRemove.empty() || !Config.DumpSection.empty() || - !Config.AddSection.empty()) { + !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty()) { return createStringError( llvm::errc::invalid_argument, - "no flags are supported yet other than basic copying"); + "only add-section, dump-section, and remove-section are supported"); } return Error::success(); }