forked from OSchip/llvm-project
[objcopy] Refactor CommonConfig to add posibility to specify added/updated sections as MemoryBuffer.
Current objcopy implementation has a possibility to add or update sections. The incoming section is specified as a pair: section name and name of the file containing section data. The interface does not allow to specify incoming section as a memory buffer. This patch adds possibility to specify incoming section as a memory buffer. Differential Revision: https://reviews.llvm.org/D120486
This commit is contained in:
parent
7b74123a3d
commit
a6f3fedc3f
|
@ -18,6 +18,7 @@
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Object/ELFTypes.h"
|
#include "llvm/Object/ELFTypes.h"
|
||||||
#include "llvm/Support/GlobPattern.h"
|
#include "llvm/Support/GlobPattern.h"
|
||||||
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/Regex.h"
|
#include "llvm/Support/Regex.h"
|
||||||
// Necessary for llvm::DebugCompressionType::None
|
// Necessary for llvm::DebugCompressionType::None
|
||||||
#include "llvm/Target/TargetOptions.h"
|
#include "llvm/Target/TargetOptions.h"
|
||||||
|
@ -186,6 +187,16 @@ struct NewSymbolInfo {
|
||||||
std::vector<StringRef> BeforeSyms;
|
std::vector<StringRef> BeforeSyms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specify section name and section body for newly added or updated section.
|
||||||
|
struct NewSectionInfo {
|
||||||
|
NewSectionInfo() = default;
|
||||||
|
NewSectionInfo(StringRef Name, std::unique_ptr<MemoryBuffer> &&Buffer)
|
||||||
|
: SectionName(Name), SectionData(std::move(Buffer)) {}
|
||||||
|
|
||||||
|
StringRef SectionName;
|
||||||
|
std::shared_ptr<MemoryBuffer> SectionData;
|
||||||
|
};
|
||||||
|
|
||||||
// Configuration for copying/stripping a single file.
|
// Configuration for copying/stripping a single file.
|
||||||
struct CommonConfig {
|
struct CommonConfig {
|
||||||
// Main input/output options
|
// Main input/output options
|
||||||
|
@ -208,9 +219,9 @@ struct CommonConfig {
|
||||||
DiscardType DiscardMode = DiscardType::None;
|
DiscardType DiscardMode = DiscardType::None;
|
||||||
|
|
||||||
// Repeated options
|
// Repeated options
|
||||||
std::vector<StringRef> AddSection;
|
std::vector<NewSectionInfo> AddSection;
|
||||||
std::vector<StringRef> DumpSection;
|
std::vector<StringRef> DumpSection;
|
||||||
std::vector<StringRef> UpdateSection;
|
std::vector<NewSectionInfo> UpdateSection;
|
||||||
|
|
||||||
// Section matchers
|
// Section matchers
|
||||||
NameMatcher KeepSection;
|
NameMatcher KeepSection;
|
||||||
|
|
|
@ -230,56 +230,41 @@ static Error handleArgs(const CommonConfig &Config,
|
||||||
It->second.NewFlags, Sec.Header.Characteristics);
|
It->second.NewFlags, Sec.Header.Characteristics);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &Flag : Config.AddSection) {
|
for (const NewSectionInfo &NewSection : 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);
|
|
||||||
|
|
||||||
uint32_t Characteristics;
|
uint32_t Characteristics;
|
||||||
const auto It = Config.SetSectionFlags.find(SecName);
|
const auto It = Config.SetSectionFlags.find(NewSection.SectionName);
|
||||||
if (It != Config.SetSectionFlags.end())
|
if (It != Config.SetSectionFlags.end())
|
||||||
Characteristics = flagsToCharacteristics(It->second.NewFlags, 0);
|
Characteristics = flagsToCharacteristics(It->second.NewFlags, 0);
|
||||||
else
|
else
|
||||||
Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES;
|
Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES;
|
||||||
|
|
||||||
addSection(
|
addSection(Obj, NewSection.SectionName,
|
||||||
Obj, SecName,
|
makeArrayRef(reinterpret_cast<const uint8_t *>(
|
||||||
makeArrayRef(reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
|
NewSection.SectionData->getBufferStart()),
|
||||||
Buf->getBufferSize()),
|
NewSection.SectionData->getBufferSize()),
|
||||||
Characteristics);
|
Characteristics);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StringRef Flag : Config.UpdateSection) {
|
for (const NewSectionInfo &NewSection : Config.UpdateSection) {
|
||||||
StringRef SecName, FileName;
|
auto It = llvm::find_if(Obj.getMutableSections(), [&](auto &Sec) {
|
||||||
std::tie(SecName, FileName) = Flag.split('=');
|
return Sec.Name == NewSection.SectionName;
|
||||||
|
|
||||||
auto BufOrErr = MemoryBuffer::getFile(FileName);
|
|
||||||
if (!BufOrErr)
|
|
||||||
return createFileError(FileName, errorCodeToError(BufOrErr.getError()));
|
|
||||||
auto Buf = std::move(*BufOrErr);
|
|
||||||
|
|
||||||
auto It = llvm::find_if(Obj.getMutableSections(), [SecName](auto &Sec) {
|
|
||||||
return Sec.Name == SecName;
|
|
||||||
});
|
});
|
||||||
if (It == Obj.getMutableSections().end())
|
if (It == Obj.getMutableSections().end())
|
||||||
return createStringError(errc::invalid_argument,
|
return createStringError(errc::invalid_argument,
|
||||||
"could not find section with name '%s'",
|
"could not find section with name '%s'",
|
||||||
SecName.str().c_str());
|
NewSection.SectionName.str().c_str());
|
||||||
size_t ContentSize = It->getContents().size();
|
size_t ContentSize = It->getContents().size();
|
||||||
if (!ContentSize)
|
if (!ContentSize)
|
||||||
return createStringError(
|
return createStringError(
|
||||||
errc::invalid_argument,
|
errc::invalid_argument,
|
||||||
"section '%s' cannot be updated because it does not have contents",
|
"section '%s' cannot be updated because it does not have contents",
|
||||||
SecName.str().c_str());
|
NewSection.SectionName.str().c_str());
|
||||||
if (ContentSize < Buf->getBufferSize())
|
if (ContentSize < NewSection.SectionData->getBufferSize())
|
||||||
return createStringError(
|
return createStringError(
|
||||||
errc::invalid_argument,
|
errc::invalid_argument,
|
||||||
"new section cannot be larger than previous section");
|
"new section cannot be larger than previous section");
|
||||||
It->setOwnedContents({Buf->getBufferStart(), Buf->getBufferEnd()});
|
It->setOwnedContents({NewSection.SectionData->getBufferStart(),
|
||||||
|
NewSection.SectionData->getBufferEnd()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.AddGnuDebugLink.empty())
|
if (!Config.AddGnuDebugLink.empty())
|
||||||
|
|
|
@ -586,19 +586,12 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error
|
static Error
|
||||||
handleUserSection(StringRef Flag,
|
handleUserSection(const NewSectionInfo &NewSection,
|
||||||
function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
|
function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
|
||||||
std::pair<StringRef, StringRef> SecPair = Flag.split("=");
|
ArrayRef<uint8_t> Data(reinterpret_cast<const uint8_t *>(
|
||||||
StringRef SecName = SecPair.first;
|
NewSection.SectionData->getBufferStart()),
|
||||||
StringRef File = SecPair.second;
|
NewSection.SectionData->getBufferSize());
|
||||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = MemoryBuffer::getFile(File);
|
return F(NewSection.SectionName, Data);
|
||||||
if (!BufOrErr)
|
|
||||||
return createFileError(File, errorCodeToError(BufOrErr.getError()));
|
|
||||||
std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
|
|
||||||
ArrayRef<uint8_t> Data(
|
|
||||||
reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
|
|
||||||
Buf->getBufferSize());
|
|
||||||
return F(SecName, Data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function handles the high level operations of GNU objcopy including
|
// This function handles the high level operations of GNU objcopy including
|
||||||
|
@ -717,7 +710,7 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
|
||||||
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
|
if (Sec.Flags & SHF_ALLOC && Sec.Type != SHT_NOTE)
|
||||||
Sec.Type = SHT_NOBITS;
|
Sec.Type = SHT_NOBITS;
|
||||||
|
|
||||||
for (const auto &Flag : Config.AddSection) {
|
for (const NewSectionInfo &AddedSection : Config.AddSection) {
|
||||||
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
|
auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
|
||||||
OwnedDataSection &NewSection =
|
OwnedDataSection &NewSection =
|
||||||
Obj.addSection<OwnedDataSection>(Name, Data);
|
Obj.addSection<OwnedDataSection>(Name, Data);
|
||||||
|
@ -725,15 +718,15 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
|
||||||
NewSection.Type = SHT_NOTE;
|
NewSection.Type = SHT_NOTE;
|
||||||
return Error::success();
|
return Error::success();
|
||||||
};
|
};
|
||||||
if (Error E = handleUserSection(Flag, AddSection))
|
if (Error E = handleUserSection(AddedSection, AddSection))
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StringRef Flag : Config.UpdateSection) {
|
for (const NewSectionInfo &NewSection : Config.UpdateSection) {
|
||||||
auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
|
auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
|
||||||
return Obj.updateSection(Name, Data);
|
return Obj.updateSection(Name, Data);
|
||||||
};
|
};
|
||||||
if (Error E = handleUserSection(Flag, UpdateSection))
|
if (Error E = handleUserSection(NewSection, UpdateSection))
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ static void updateAndRemoveSymbols(const CommonConfig &Config,
|
||||||
Sym.Name = std::string(I->getValue());
|
Sym.Name = std::string(I->getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RemovePred = [Config, MachOConfig,
|
auto RemovePred = [&Config, &MachOConfig,
|
||||||
&Obj](const std::unique_ptr<SymbolEntry> &N) {
|
&Obj](const std::unique_ptr<SymbolEntry> &N) {
|
||||||
if (N->Referenced)
|
if (N->Referenced)
|
||||||
return false;
|
return false;
|
||||||
|
@ -283,17 +283,12 @@ static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||||
SecName.str().c_str());
|
SecName.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
|
static Error addSection(const NewSectionInfo &NewSection, Object &Obj) {
|
||||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
std::pair<StringRef, StringRef> Pair = NewSection.SectionName.split(',');
|
||||||
MemoryBuffer::getFile(Filename);
|
|
||||||
if (!BufOrErr)
|
|
||||||
return createFileError(Filename, errorCodeToError(BufOrErr.getError()));
|
|
||||||
std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
|
|
||||||
|
|
||||||
std::pair<StringRef, StringRef> Pair = SecName.split(',');
|
|
||||||
StringRef TargetSegName = Pair.first;
|
StringRef TargetSegName = Pair.first;
|
||||||
Section Sec(TargetSegName, Pair.second);
|
Section Sec(TargetSegName, Pair.second);
|
||||||
Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer());
|
Sec.Content =
|
||||||
|
Obj.NewSectionsContents.save(NewSection.SectionData->getBuffer());
|
||||||
Sec.Size = Sec.Content.size();
|
Sec.Size = Sec.Content.size();
|
||||||
|
|
||||||
// Add the a section into an existing segment.
|
// Add the a section into an existing segment.
|
||||||
|
@ -342,24 +337,18 @@ static Expected<Section &> findSection(StringRef SecName, Object &O) {
|
||||||
return *FoundSec->get();
|
return *FoundSec->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error updateSection(StringRef SecName, StringRef Filename, Object &O) {
|
static Error updateSection(const NewSectionInfo &NewSection, Object &O) {
|
||||||
Expected<Section &> SecToUpdateOrErr = findSection(SecName, O);
|
Expected<Section &> SecToUpdateOrErr = findSection(NewSection.SectionName, O);
|
||||||
|
|
||||||
if (!SecToUpdateOrErr)
|
if (!SecToUpdateOrErr)
|
||||||
return SecToUpdateOrErr.takeError();
|
return SecToUpdateOrErr.takeError();
|
||||||
Section &Sec = *SecToUpdateOrErr;
|
Section &Sec = *SecToUpdateOrErr;
|
||||||
|
|
||||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
if (NewSection.SectionData->getBufferSize() > Sec.Size)
|
||||||
MemoryBuffer::getFile(Filename);
|
|
||||||
if (!BufOrErr)
|
|
||||||
return createFileError(Filename, errorCodeToError(BufOrErr.getError()));
|
|
||||||
std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
|
|
||||||
|
|
||||||
if (Buf->getBufferSize() > Sec.Size)
|
|
||||||
return createStringError(
|
return createStringError(
|
||||||
errc::invalid_argument,
|
errc::invalid_argument,
|
||||||
"new section cannot be larger than previous section");
|
"new section cannot be larger than previous section");
|
||||||
Sec.Content = O.NewSectionsContents.save(Buf->getBuffer());
|
Sec.Content = O.NewSectionsContents.save(NewSection.SectionData->getBuffer());
|
||||||
Sec.Size = Sec.Content.size();
|
Sec.Size = Sec.Content.size();
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
@ -411,23 +400,17 @@ static Error handleArgs(const CommonConfig &Config,
|
||||||
for (std::unique_ptr<Section> &Sec : LC.Sections)
|
for (std::unique_ptr<Section> &Sec : LC.Sections)
|
||||||
Sec->Relocations.clear();
|
Sec->Relocations.clear();
|
||||||
|
|
||||||
for (const auto &Flag : Config.AddSection) {
|
for (const NewSectionInfo &NewSection : Config.AddSection) {
|
||||||
std::pair<StringRef, StringRef> SecPair = Flag.split("=");
|
if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
|
||||||
StringRef SecName = SecPair.first;
|
|
||||||
StringRef File = SecPair.second;
|
|
||||||
if (Error E = isValidMachOCannonicalName(SecName))
|
|
||||||
return E;
|
return E;
|
||||||
if (Error E = addSection(SecName, File, Obj))
|
if (Error E = addSection(NewSection, Obj))
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &Flag : Config.UpdateSection) {
|
for (const NewSectionInfo &NewSection : Config.UpdateSection) {
|
||||||
StringRef SectionName;
|
if (Error E = isValidMachOCannonicalName(NewSection.SectionName))
|
||||||
StringRef FileName;
|
|
||||||
std::tie(SectionName, FileName) = Flag.split('=');
|
|
||||||
if (Error E = isValidMachOCannonicalName(SectionName))
|
|
||||||
return E;
|
return E;
|
||||||
if (Error E = updateSection(SectionName, FileName, Obj))
|
if (Error E = updateSection(NewSection, Obj))
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,21 +121,19 @@ static Error handleArgs(const CommonConfig &Config, Object &Obj) {
|
||||||
|
|
||||||
removeSections(Config, Obj);
|
removeSections(Config, Obj);
|
||||||
|
|
||||||
for (StringRef Flag : Config.AddSection) {
|
for (const NewSectionInfo &NewSection : 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;
|
Section Sec;
|
||||||
Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM;
|
Sec.SectionType = llvm::wasm::WASM_SEC_CUSTOM;
|
||||||
Sec.Name = SecName;
|
Sec.Name = NewSection.SectionName;
|
||||||
std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
|
|
||||||
|
std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy(
|
||||||
|
NewSection.SectionData->getBufferStart(),
|
||||||
|
NewSection.SectionData->getBufferIdentifier());
|
||||||
Sec.Contents = makeArrayRef<uint8_t>(
|
Sec.Contents = makeArrayRef<uint8_t>(
|
||||||
reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
|
reinterpret_cast<const uint8_t *>(BufferCopy->getBufferStart()),
|
||||||
Buf->getBufferSize());
|
BufferCopy->getBufferSize());
|
||||||
Obj.addSectionWithOwnedContents(Sec, std::move(Buf));
|
|
||||||
|
Obj.addSectionWithOwnedContents(Sec, std::move(BufferCopy));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
|
@ -59,9 +59,9 @@
|
||||||
|
|
||||||
## Test that llvm-objcopy produces an error if the file with section contents
|
## Test that llvm-objcopy produces an error if the file with section contents
|
||||||
## to be added does not exist.
|
## to be added does not exist.
|
||||||
# RUN: not llvm-objcopy --add-section=.another.section=%t2 %t %t3 2>&1 | FileCheck -DFILE1=%t -DFILE2=%t2 -DMSG=%errc_ENOENT %s --check-prefixes=ERR1
|
# RUN: not llvm-objcopy --add-section=.another.section=%t2 %t %t3 2>&1 | FileCheck -DFILE=%t2 -DMSG=%errc_ENOENT %s --check-prefixes=ERR1
|
||||||
|
|
||||||
# ERR1: error: '[[FILE1]]': '[[FILE2]]': [[MSG]]
|
# ERR1: error: '[[FILE]]': [[MSG]]
|
||||||
|
|
||||||
## Another negative test for invalid --add-sections command line argument.
|
## Another negative test for invalid --add-sections command line argument.
|
||||||
# RUN: not llvm-objcopy --add-section=.another.section %t %t3 2>&1 | FileCheck %s --check-prefixes=ERR2
|
# RUN: not llvm-objcopy --add-section=.another.section %t %t3 2>&1 | FileCheck %s --check-prefixes=ERR2
|
||||||
|
|
|
@ -49,9 +49,9 @@ Sections:
|
||||||
|
|
||||||
## Test that llvm-objcopy produces an error if the file with section contents
|
## Test that llvm-objcopy produces an error if the file with section contents
|
||||||
## to be added does not exist.
|
## to be added does not exist.
|
||||||
# RUN: not llvm-objcopy --add-section=.section.name=%t.missing %t %t.out 2>&1 | FileCheck -DFILE1=%t -DFILE2=%t.missing -DMSG=%errc_ENOENT %s --check-prefixes=ERR1
|
# RUN: not llvm-objcopy --add-section=.section.name=%t.missing %t %t.out 2>&1 | FileCheck -DFILE=%t.missing -DMSG=%errc_ENOENT %s --check-prefixes=ERR1
|
||||||
|
|
||||||
# ERR1: error: '[[FILE1]]': '[[FILE2]]': [[MSG]]
|
# ERR1: error: '[[FILE]]': [[MSG]]
|
||||||
|
|
||||||
## Negative test for invalid --add-sections argument - missing '='.
|
## Negative test for invalid --add-sections argument - missing '='.
|
||||||
# RUN: not llvm-objcopy --add-section=.section.name %t %t.out 2>&1 | FileCheck %s --check-prefixes=ERR2
|
# RUN: not llvm-objcopy --add-section=.section.name %t %t.out 2>&1 | FileCheck %s --check-prefixes=ERR2
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
## Error case 1: Nonexistent input file is specified by --add-section.
|
## Error case 1: Nonexistent input file is specified by --add-section.
|
||||||
# RUN: not llvm-objcopy --add-section __TEXT,__text=%t.missing %t %t.nonexistent-file 2>&1 \
|
# RUN: not llvm-objcopy --add-section __TEXT,__text=%t.missing %t %t.nonexistent-file 2>&1 \
|
||||||
# RUN: | FileCheck %s -DINPUT=%t -DSECTION_DATA_FILE=%t.missing -DMSG=%errc_ENOENT --check-prefix=NONEXSITENT-FILE
|
# RUN: | FileCheck %s -DINPUT=%t -DSECTION_DATA_FILE=%t.missing -DMSG=%errc_ENOENT --check-prefix=NONEXSITENT-FILE
|
||||||
# NONEXSITENT-FILE: error: '[[INPUT]]': '[[SECTION_DATA_FILE]]': [[MSG]]
|
# NONEXSITENT-FILE: error: '[[SECTION_DATA_FILE]]': [[MSG]]
|
||||||
|
|
||||||
## Error case 2: Too long segment name.
|
## Error case 2: Too long segment name.
|
||||||
# RUN: not llvm-objcopy --add-section __TOOOOOOOOO_LONG,__text=%t.data %t %t.too-long-seg-name 2>&1 \
|
# RUN: not llvm-objcopy --add-section __TOOOOOOOOO_LONG,__text=%t.data %t %t.too-long-seg-name 2>&1 \
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
# RUN: llvm-objcopy --update-section __TEXT,__text=%t.diff %t - | obj2yaml | FileCheck %s --check-prefix=FULL-SECNAME
|
# RUN: llvm-objcopy --update-section __TEXT,__text=%t.diff %t - | obj2yaml | FileCheck %s --check-prefix=FULL-SECNAME
|
||||||
# FULL-SECNAME: content: '41414142'
|
# FULL-SECNAME: content: '41414142'
|
||||||
|
|
||||||
# RUN: not llvm-objcopy --update-section __text=%t.dff %t /dev/null 2>&1 | FileCheck %s --check-prefix=NON-CANONICAL-SECNAME
|
# RUN: not llvm-objcopy --update-section __text=%t.diff %t /dev/null 2>&1 | FileCheck %s --check-prefix=NON-CANONICAL-SECNAME
|
||||||
# NON-CANONICAL-SECNAME: error: {{.*}}invalid section name '__text' (should be formatted as '<segment name>,<section name>')
|
# NON-CANONICAL-SECNAME: error: {{.*}}invalid section name '__text' (should be formatted as '<segment name>,<section name>')
|
||||||
|
|
||||||
--- !mach-o
|
--- !mach-o
|
||||||
|
|
|
@ -558,6 +558,32 @@ static Expected<NewSymbolInfo> parseNewSymbolInfo(StringRef FlagValue) {
|
||||||
return SI;
|
return SI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse input option \p ArgValue and load section data. This function
|
||||||
|
// extracts section name and name of the file keeping section data from
|
||||||
|
// ArgValue, loads data from the file, and stores section name and data
|
||||||
|
// into the vector of new sections \p NewSections.
|
||||||
|
static Error loadNewSectionData(StringRef ArgValue, StringRef OptionName,
|
||||||
|
std::vector<NewSectionInfo> &NewSections) {
|
||||||
|
if (!ArgValue.contains('='))
|
||||||
|
return createStringError(errc::invalid_argument,
|
||||||
|
"bad format for " + OptionName + ": missing '='");
|
||||||
|
|
||||||
|
std::pair<StringRef, StringRef> SecPair = ArgValue.split("=");
|
||||||
|
if (SecPair.second.empty())
|
||||||
|
return createStringError(errc::invalid_argument, "bad format for " +
|
||||||
|
OptionName +
|
||||||
|
": missing file name");
|
||||||
|
|
||||||
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
||||||
|
MemoryBuffer::getFile(SecPair.second);
|
||||||
|
if (!BufOrErr)
|
||||||
|
return createFileError(SecPair.second,
|
||||||
|
errorCodeToError(BufOrErr.getError()));
|
||||||
|
|
||||||
|
NewSections.push_back({SecPair.first, std::move(*BufOrErr)});
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
// ParseObjcopyOptions returns the config and sets the input arguments. If a
|
// ParseObjcopyOptions returns the config and sets the input arguments. If a
|
||||||
// help flag is set then ParseObjcopyOptions will print the help messege and
|
// help flag is set then ParseObjcopyOptions will print the help messege and
|
||||||
// exit.
|
// exit.
|
||||||
|
@ -848,26 +874,14 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
|
||||||
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
|
Arg->getValue(), SectionMatchStyle, ErrorCallback)))
|
||||||
return std::move(E);
|
return std::move(E);
|
||||||
for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
|
for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
|
||||||
StringRef ArgValue(Arg->getValue());
|
if (Error Err = loadNewSectionData(Arg->getValue(), "--add-section",
|
||||||
if (!ArgValue.contains('='))
|
Config.AddSection))
|
||||||
return createStringError(errc::invalid_argument,
|
return std::move(Err);
|
||||||
"bad format for --add-section: missing '='");
|
|
||||||
if (ArgValue.split("=").second.empty())
|
|
||||||
return createStringError(
|
|
||||||
errc::invalid_argument,
|
|
||||||
"bad format for --add-section: missing file name");
|
|
||||||
Config.AddSection.push_back(ArgValue);
|
|
||||||
}
|
}
|
||||||
for (auto Arg : InputArgs.filtered(OBJCOPY_update_section)) {
|
for (auto Arg : InputArgs.filtered(OBJCOPY_update_section)) {
|
||||||
StringRef ArgValue(Arg->getValue());
|
if (Error Err = loadNewSectionData(Arg->getValue(), "--update-section",
|
||||||
if (!ArgValue.contains('='))
|
Config.UpdateSection))
|
||||||
return createStringError(errc::invalid_argument,
|
return std::move(Err);
|
||||||
"bad format for --update-section: missing '='");
|
|
||||||
if (ArgValue.split("=").second.empty())
|
|
||||||
return createStringError(
|
|
||||||
errc::invalid_argument,
|
|
||||||
"bad format for --update-section: missing file name");
|
|
||||||
Config.UpdateSection.push_back(ArgValue);
|
|
||||||
}
|
}
|
||||||
for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {
|
for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {
|
||||||
StringRef Value(Arg->getValue());
|
StringRef Value(Arg->getValue());
|
||||||
|
|
|
@ -116,3 +116,252 @@ FileHeader:
|
||||||
)",
|
)",
|
||||||
[](const Binary &File) { return File.isWasm(); });
|
[](const Binary &File) { return File.isWasm(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Action : uint8_t { AddSection, UpdateSection };
|
||||||
|
|
||||||
|
void addOrUpdateSectionToFileImpl(
|
||||||
|
const char *YamlCreationString,
|
||||||
|
std::function<bool(const Binary &File)> IsValidFormat,
|
||||||
|
StringRef NewSectionName, StringRef NewSectionData, Action SectionAction) {
|
||||||
|
auto ErrHandler = [&](const Twine &Msg) { FAIL() << "Error: " << Msg; };
|
||||||
|
|
||||||
|
// Create Object file from YAML description.
|
||||||
|
SmallVector<char> Storage;
|
||||||
|
std::unique_ptr<ObjectFile> Obj =
|
||||||
|
yaml2ObjectFile(Storage, YamlCreationString, ErrHandler);
|
||||||
|
ASSERT_TRUE(Obj);
|
||||||
|
ASSERT_TRUE(IsValidFormat(*Obj));
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryBuffer> NewSectionBuffer =
|
||||||
|
MemoryBuffer::getMemBuffer(NewSectionData, NewSectionName, false);
|
||||||
|
std::string Name;
|
||||||
|
if (Obj->isMachO())
|
||||||
|
Name = "__TEXT," + NewSectionName.str();
|
||||||
|
else
|
||||||
|
Name = NewSectionName.str();
|
||||||
|
|
||||||
|
ConfigManager Config;
|
||||||
|
Config.Common.OutputFilename = "a.out";
|
||||||
|
if (SectionAction == AddSection)
|
||||||
|
Config.Common.AddSection.push_back({Name, std::move(NewSectionBuffer)});
|
||||||
|
else
|
||||||
|
Config.Common.UpdateSection.push_back({Name, std::move(NewSectionBuffer)});
|
||||||
|
|
||||||
|
// Call executeObjcopyOnBinary()
|
||||||
|
SmallVector<char> DataVector;
|
||||||
|
raw_svector_ostream OutStream(DataVector);
|
||||||
|
Error Err = objcopy::executeObjcopyOnBinary(Config, *Obj.get(), OutStream);
|
||||||
|
ASSERT_FALSE(std::move(Err));
|
||||||
|
|
||||||
|
MemoryBufferRef Buffer(StringRef(DataVector.data(), DataVector.size()),
|
||||||
|
Config.Common.OutputFilename);
|
||||||
|
|
||||||
|
// Check copied file.
|
||||||
|
Expected<std::unique_ptr<Binary>> Result = createBinary(Buffer);
|
||||||
|
ASSERT_THAT_EXPECTED(Result, Succeeded());
|
||||||
|
ASSERT_TRUE(IsValidFormat(**Result));
|
||||||
|
ASSERT_TRUE((*Result)->isObject());
|
||||||
|
|
||||||
|
// Check that copied file has the new section.
|
||||||
|
bool HasNewSection = false;
|
||||||
|
for (const object::SectionRef &Sect :
|
||||||
|
static_cast<ObjectFile *>((*Result).get())->sections()) {
|
||||||
|
Expected<StringRef> SectNameOrErr = Sect.getName();
|
||||||
|
ASSERT_THAT_EXPECTED(SectNameOrErr, Succeeded());
|
||||||
|
|
||||||
|
if (*SectNameOrErr == NewSectionName) {
|
||||||
|
HasNewSection = true;
|
||||||
|
Expected<StringRef> SectionData = Sect.getContents();
|
||||||
|
ASSERT_THAT_EXPECTED(SectionData, Succeeded());
|
||||||
|
EXPECT_TRUE(Sect.getSize() == NewSectionData.size());
|
||||||
|
EXPECT_TRUE(memcmp(SectionData->data(), NewSectionData.data(),
|
||||||
|
NewSectionData.size()) == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(HasNewSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AddSection, COFF) {
|
||||||
|
SCOPED_TRACE("addSectionToFileCOFF");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !COFF
|
||||||
|
header:
|
||||||
|
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||||
|
Characteristics: [ ]
|
||||||
|
sections:
|
||||||
|
- Name: .text
|
||||||
|
Characteristics: [ ]
|
||||||
|
Alignment: 4
|
||||||
|
SectionData: E800000000C3C3C3
|
||||||
|
symbols:
|
||||||
|
...
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isCOFF(); }, ".foo", "1234",
|
||||||
|
AddSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AddSection, ELF) {
|
||||||
|
SCOPED_TRACE("addSectionToFileELF");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_REL)",
|
||||||
|
[](const Binary &File) { return File.isELF(); }, ".foo", "1234",
|
||||||
|
AddSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AddSection, MachO) {
|
||||||
|
SCOPED_TRACE("addSectionToFileMachO");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x01000007
|
||||||
|
cpusubtype: 0x80000003
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 1
|
||||||
|
sizeofcmds: 152
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: __TEXT
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 4
|
||||||
|
fileoff: 184
|
||||||
|
filesize: 4
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __text
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
content: 'AABBCCDD'
|
||||||
|
size: 4
|
||||||
|
offset: 184
|
||||||
|
align: 0
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
...
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isMachO(); }, "__foo", "1234",
|
||||||
|
AddSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AddSection, Wasm) {
|
||||||
|
SCOPED_TRACE("addSectionToFileWasm");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !WASM
|
||||||
|
FileHeader:
|
||||||
|
Version: 0x00000001
|
||||||
|
...
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isWasm(); }, ".foo", "1234",
|
||||||
|
AddSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UpdateSection, COFF) {
|
||||||
|
SCOPED_TRACE("updateSectionToFileCOFF");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !COFF
|
||||||
|
header:
|
||||||
|
Machine: IMAGE_FILE_MACHINE_AMD64
|
||||||
|
Characteristics: [ ]
|
||||||
|
sections:
|
||||||
|
- Name: .foo
|
||||||
|
Characteristics: [ ]
|
||||||
|
Alignment: 4
|
||||||
|
SectionData: E800000000C3C3C3
|
||||||
|
symbols:
|
||||||
|
...
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isCOFF(); }, ".foo", "1234",
|
||||||
|
UpdateSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UpdateSection, ELF) {
|
||||||
|
SCOPED_TRACE("updateSectionToFileELF");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_REL
|
||||||
|
Sections:
|
||||||
|
- Name: .foo
|
||||||
|
Type: SHT_PROGBITS
|
||||||
|
Flags: [ SHF_ALLOC ]
|
||||||
|
Content: "12345678"
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isELF(); }, ".foo", "1234",
|
||||||
|
UpdateSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UpdateSection, MachO) {
|
||||||
|
SCOPED_TRACE("updateSectionToFileMachO");
|
||||||
|
|
||||||
|
addOrUpdateSectionToFileImpl(
|
||||||
|
R"(
|
||||||
|
--- !mach-o
|
||||||
|
FileHeader:
|
||||||
|
magic: 0xFEEDFACF
|
||||||
|
cputype: 0x01000007
|
||||||
|
cpusubtype: 0x80000003
|
||||||
|
filetype: 0x00000001
|
||||||
|
ncmds: 1
|
||||||
|
sizeofcmds: 152
|
||||||
|
flags: 0x00002000
|
||||||
|
reserved: 0x00000000
|
||||||
|
LoadCommands:
|
||||||
|
- cmd: LC_SEGMENT_64
|
||||||
|
cmdsize: 152
|
||||||
|
segname: __TEXT
|
||||||
|
vmaddr: 0
|
||||||
|
vmsize: 4
|
||||||
|
fileoff: 184
|
||||||
|
filesize: 4
|
||||||
|
maxprot: 7
|
||||||
|
initprot: 7
|
||||||
|
nsects: 1
|
||||||
|
flags: 0
|
||||||
|
Sections:
|
||||||
|
- sectname: __foo
|
||||||
|
segname: __TEXT
|
||||||
|
addr: 0x0000000000000000
|
||||||
|
content: 'AABBCCDD'
|
||||||
|
size: 4
|
||||||
|
offset: 184
|
||||||
|
align: 0
|
||||||
|
reloff: 0x00000000
|
||||||
|
nreloc: 0
|
||||||
|
flags: 0x80000400
|
||||||
|
reserved1: 0x00000000
|
||||||
|
reserved2: 0x00000000
|
||||||
|
reserved3: 0x00000000
|
||||||
|
...
|
||||||
|
)",
|
||||||
|
[](const Binary &File) { return File.isMachO(); }, "__foo", "1234",
|
||||||
|
UpdateSection);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue