Index: test/tools/llvm-objcopy/add-section-remove.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/add-section-remove.test @@ -0,0 +1,36 @@ +# RUN: yaml2obj %s > %t +# RUN: echo 0000 > %t.sec +# RUN: llvm-objcopy -R=.test2 -add-section=.test2=%t.sec %t %t2 +# RUN: llvm-readobj -file-headers -sections -section-data %t2 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test1 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "c3c3c3c3" + - Name: .test2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "DEADBEEF" + - Name: .test3 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "32323232" + +# CHECK: SectionHeaderCount: 7 + +# CHECK: Name: .test1 +# CHECK: Name: .test3 +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab +# CHECK: Name: .test2 +# CHECK: SectionData ( +# CHECK-NEXT: 0000: 30303030 +# CHECK-NEXT: ) Index: test/tools/llvm-objcopy/add-section.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/add-section.test @@ -0,0 +1,37 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy -O binary -j .test2 %t %t.sec +# RUN: llvm-objcopy -R=.test2 %t %t2 +# RUN: llvm-objcopy -add-section=.test2=%t.sec %t2 %t3 +# RUN: llvm-readobj -file-headers -sections -section-data %t3 | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .test1 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "c3c3c3c3" + - Name: .test2 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "DEADBEEF" + - Name: .test3 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Content: "32323232" + +# CHECK: SectionHeaderCount: 7 + +# CHECK: Name: .test1 +# CHECK: Name: .test3 +# CHECK: Name: .symtab +# CHECK: Name: .strtab +# CHECK: Name: .shstrtab +# CHECK: Name: .test2 +# CHECK: SectionData ( +# CHECK-NEXT: 0000: DEADBEEF +# CHECK-NEXT: ) Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -126,6 +126,20 @@ void writeSection(FileOutputBuffer &Out) const override; }; +class OwnedDataSection : public SectionBase { +private: + std::vector Data; + +public: + OwnedDataSection(StringRef SecName, ArrayRef Data) + : Data(std::begin(Data), std::end(Data)) { + Name = SecName; + Type = ELF::SHT_PROGBITS; + Size = Data.size(); + } + void writeSection(FileOutputBuffer &Out) const override; +}; + // There are two types of string tables that can exist, dynamic and not dynamic. // In the dynamic case the string table is allocated. Changing a dynamic string // table would mean altering virtual addresses and thus the memory image. So @@ -372,6 +386,7 @@ const SymbolTableSection *getSymTab() const { return SymbolTable; } const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function ToRemove); + void addSection(StringRef SecName, ArrayRef Data); virtual size_t totalSize() const = 0; virtual void finalize() = 0; virtual void write(FileOutputBuffer &Out) const = 0; Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -81,6 +81,11 @@ std::copy(std::begin(Contents), std::end(Contents), Buf); } +void OwnedDataSection::writeSection(FileOutputBuffer &Out) const { + uint8_t *Buf = Out.getBufferStart() + Offset; + std::copy(std::begin(Data), std::end(Data), Buf); +} + void StringTableSection::addString(StringRef Name) { StrTabBuilder.add(Name); Size = StrTabBuilder.getSize(); @@ -676,6 +681,13 @@ Sections.erase(Iter, std::end(Sections)); } +template +void Object::addSection(StringRef SecName, ArrayRef Data) { + auto Sec = llvm::make_unique(SecName, Data); + Sec->OriginalOffset = ~0ULL; + Sections.push_back(std::move(Sec)); +} + template void ELFObject::sortSections() { // Put all sections in offset order. Maintain the ordering as closely as // possible while meeting that demand however. Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -113,6 +113,10 @@ cl::desc("Equivalent to extract-dwo on the input file to " ", then strip-dwo on the input file"), cl::value_desc("dwo-file")); +static cl::list AddSection( + "add-section", + cl::desc("Make a section named
with the contents of ."), + cl::value_desc("section=file")); using SectionPred = std::function; @@ -174,7 +178,7 @@ Obj = llvm::make_unique>(ObjFile); if (!SplitDWO.empty()) - SplitDWOToFile(ObjFile, SplitDWO.getValue()); + SplitDWOToFile(ObjFile, SplitDWO.getValue()); SectionPred RemovePred = [](const SectionBase &) { return false; }; @@ -284,8 +288,24 @@ return RemovePred(Sec); }; } - + Obj->removeSections(RemovePred); + + if (!AddSection.empty()) { + for (const auto &Flag : AddSection) { + auto SecPair = StringRef(Flag).split("="); + auto SecName = SecPair.first; + auto File = SecPair.second; + auto BufOrErr = MemoryBuffer::getFile(File); + if (!BufOrErr) + reportError(File, BufOrErr.getError()); + auto Buf = std::move(*BufOrErr); + auto BufPtr = reinterpret_cast(Buf->getBufferStart()); + auto BufSize = Buf->getBufferSize(); + Obj->addSection(SecName, ArrayRef(BufPtr, BufSize)); + } + } + Obj->finalize(); WriteObjectFile(*Obj, OutputFilename.getValue()); }