mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
[llvm-objcopy][WebAssembly] Add dump/add/remove-section support
Add support for adding, removing, and dumping wasm sections to objcopy Differential Revision: https://reviews.llvm.org/D70970
This commit is contained in:
parent
0e4d775a3f
commit
0e37f48abc
83
test/tools/llvm-objcopy/wasm/add-section.test
Normal file
83
test/tools/llvm-objcopy/wasm/add-section.test
Normal file
@ -0,0 +1,83 @@
|
||||
## Test --add-section. This test dumps and removes 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 --remove-section=producers %t %t2
|
||||
# RUN: llvm-objcopy --add-section=producers=%t.sec %t2 %t3
|
||||
# RUN: obj2yaml %t3 | FileCheck %s
|
||||
|
||||
## 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
|
||||
|
||||
# Check that the section is replaced with new content in one invocation.
|
||||
# RUN: echo "123" > %t4
|
||||
# RUN: llvm-objcopy --remove-section=foo --add-section=foo=%t4 %t %t5
|
||||
# RUN: obj2yaml %t5 | FileCheck %s --check-prefix=REPLACE
|
||||
|
||||
# REPLACE: - Type: CUSTOM
|
||||
# REPLACE: Name: foo
|
||||
# REPLACE: Payload: 3132330A
|
||||
|
||||
--- !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
|
||||
- Type: CUSTOM
|
||||
Name: foo
|
||||
Payload: ABC123
|
38
test/tools/llvm-objcopy/wasm/dump-section.test
Normal file
38
test/tools/llvm-objcopy/wasm/dump-section.test
Normal file
@ -0,0 +1,38 @@
|
||||
## 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
|
||||
|
||||
# RUN: not llvm-objcopy --dump-section=nonexistent=%t.sec %t 2>&1 | FileCheck --check-prefix=NONEXISTENT %s
|
||||
# RUN: not llvm-objcopy --dump-section=producers=%t.dir/bar %t 2>&1 | FileCheck --check-prefix=DIROUT %s
|
||||
|
||||
## Raw 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
|
||||
|
||||
# NONEXISTENT: section 'nonexistent' not found
|
||||
# DIROUT: error: {{.*}}/bar': {{[nN]}}o such file or directory
|
||||
|
||||
## Check that dumping and removing a section works in the same invocation
|
||||
# RUN: llvm-objcopy --dump-section=producers=%t.sec --remove-section=producers %t %t2
|
||||
# RUN: od -t x1 %t.sec | FileCheck %s
|
||||
# RUN: obj2yaml %t2 | FileCheck --check-prefix=REMOVED %s
|
||||
|
||||
# REMOVED-NOT: producers
|
||||
|
||||
--- !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
|
26
test/tools/llvm-objcopy/wasm/remove-section.test
Normal file
26
test/tools/llvm-objcopy/wasm/remove-section.test
Normal file
@ -0,0 +1,26 @@
|
||||
## Test the --remove-section flag.
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: llvm-objcopy -R producers %t %t2
|
||||
# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=producers %s
|
||||
## Check that the producers section has been removed, but not the type section.
|
||||
# CHECK: TYPE
|
||||
|
||||
## Requests to remove nonexistent sections are silently ignored.
|
||||
# RUN: llvm-objcopy --remove-section=nonexistent=%t.sec %t 2&>1 | count 0
|
||||
|
||||
--- !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
|
@ -33,6 +33,7 @@ add_llvm_tool(llvm-objcopy
|
||||
MachO/MachOWriter.cpp
|
||||
MachO/MachOLayoutBuilder.cpp
|
||||
MachO/Object.cpp
|
||||
wasm/Object.cpp
|
||||
wasm/Reader.cpp
|
||||
wasm/Writer.cpp
|
||||
wasm/WasmObjcopy.cpp
|
||||
|
36
tools/llvm-objcopy/wasm/Object.cpp
Normal file
36
tools/llvm-objcopy/wasm/Object.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//===- Object.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace objcopy {
|
||||
namespace wasm {
|
||||
|
||||
using namespace object;
|
||||
using namespace llvm::wasm;
|
||||
|
||||
void Object::addSectionWithOwnedContents(
|
||||
Section NewSection, std::unique_ptr<MemoryBuffer> &&Content) {
|
||||
Sections.push_back(NewSection);
|
||||
OwnedContents.emplace_back(std::move(Content));
|
||||
}
|
||||
|
||||
void Object::removeSections(function_ref<bool(const Section &)> 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
|
@ -12,6 +12,7 @@
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Object/Wasm.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -30,6 +31,13 @@ struct Object {
|
||||
llvm::wasm::WasmObjectHeader Header;
|
||||
// For now don't discriminate between kinds of sections.
|
||||
std::vector<Section> Sections;
|
||||
|
||||
void addSectionWithOwnedContents(Section NewSection,
|
||||
std::unique_ptr<MemoryBuffer> &&Content);
|
||||
void removeSections(function_ref<bool(const Section &)> ToRemove);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<MemoryBuffer>> OwnedContents;
|
||||
};
|
||||
|
||||
} // end namespace wasm
|
||||
|
@ -21,7 +21,58 @@ namespace wasm {
|
||||
|
||||
using namespace object;
|
||||
|
||||
static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||
Object &Obj) {
|
||||
for (const Section &Sec : Obj.Sections) {
|
||||
if (Sec.Name == SecName) {
|
||||
ArrayRef<uint8_t> Contents = Sec.Contents;
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||
FileOutputBuffer::create(Filename, Contents.size());
|
||||
if (!BufferOrErr)
|
||||
return BufferOrErr.takeError();
|
||||
std::unique_ptr<FileOutputBuffer> 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 for now.
|
||||
for (StringRef Flag : Config.DumpSection) {
|
||||
StringRef SecName;
|
||||
StringRef FileName;
|
||||
std::tie(SecName, FileName) = Flag.split("=");
|
||||
if (Error E = dumpSectionToFile(SecName, FileName, Obj))
|
||||
return createFileError(FileName, std::move(E));
|
||||
}
|
||||
|
||||
Obj.removeSections([&Config](const Section &Sec) {
|
||||
if (Config.ToRemove.matches(Sec.Name))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
for (StringRef Flag : Config.AddSection) {
|
||||
StringRef SecName, FileName;
|
||||
std::tie(SecName, FileName) = Flag.split("=");
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
||||
MemoryBuffer::getFile(FileName);
|
||||
if (!BufOrErr)
|
||||
return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
|
||||
Section Sec;
|
||||
Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM;
|
||||
Sec.Name = SecName;
|
||||
std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
|
||||
Sec.Contents = makeArrayRef<uint8_t>(
|
||||
reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
|
||||
Buf->getBufferSize());
|
||||
Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
|
||||
}
|
||||
|
||||
if (!Config.AddGnuDebugLink.empty() || !Config.BuildIdLinkDir.empty() ||
|
||||
Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
|
||||
Config.ExtractPartition || !Config.SplitDWO.empty() ||
|
||||
@ -34,12 +85,10 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
!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, only basic copying is allowed");
|
||||
"only add-section, dump-section, and remove-section are supported");
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
@ -53,7 +102,7 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
Object *Obj = ObjOrErr->get();
|
||||
assert(Obj && "Unable to deserialize Wasm object");
|
||||
if (Error E = handleArgs(Config, *Obj))
|
||||
return createFileError(Config.InputFilename, std::move(E));
|
||||
return E;
|
||||
Writer TheWriter(*Obj, Out);
|
||||
if (Error E = TheWriter.write())
|
||||
return createFileError(Config.OutputFilename, std::move(E));
|
||||
|
@ -72,6 +72,7 @@ executable("llvm-objcopy") {
|
||||
"MachO/MachOWriter.cpp",
|
||||
"MachO/Object.cpp",
|
||||
"llvm-objcopy.cpp",
|
||||
"wasm/Object.cpp",
|
||||
"wasm/Reader.cpp",
|
||||
"wasm/WasmObjcopy.cpp",
|
||||
"wasm/Writer.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user