Index: test/tools/llvm-objcopy/strip-sections.test =================================================================== --- /dev/null +++ test/tools/llvm-objcopy/strip-sections.test @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-objcopy --strip-sections %t %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s +# RUN: od -t x1 -j 4096 %t2 | FileCheck %s --check-prefix=DATA + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000001000 + Content: "DEADBEEF" +ProgramHeaders: +- Type: PT_LOAD + Flags: [ PF_X, PF_R ] + Sections: + - Section: .text + +#DATA: 0010000 de ad be ef + +#CHECK: ProgramHeaders [ +#CHECK-NEXT: ProgramHeader { +#CHECK-NEXT: Type: PT_LOAD (0x1) +#CHECK-NEXT: Offset: 0x1000 +#CHECK-NEXT: VirtualAddress: 0x0 +#CHECK-NEXT: PhysicalAddress: 0x0 +#CHECK-NEXT: FileSize: 4 +#CHECK-NEXT: MemSize: 4 +#CHECK-NEXT: Flags [ (0x5) +#CHECK-NEXT: PF_R (0x4) +#CHECK-NEXT: PF_X (0x1) +#CHECK-NEXT: ] +#CHECK-NEXT: Alignment: 4096 +#CHECK-NEXT: } +#CHECK-NEXT:] Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -582,14 +582,20 @@ Ehdr.e_version = Version; Ehdr.e_entry = Entry; Ehdr.e_phoff = sizeof(Elf_Ehdr); - Ehdr.e_shoff = SHOffset; Ehdr.e_flags = Flags; Ehdr.e_ehsize = sizeof(Elf_Ehdr); Ehdr.e_phentsize = sizeof(Elf_Phdr); Ehdr.e_phnum = Segments.size(); Ehdr.e_shentsize = sizeof(Elf_Shdr); - Ehdr.e_shnum = Sections.size() + 1; - Ehdr.e_shstrndx = SectionNames->Index; + if (SectionNames != nullptr) { + Ehdr.e_shoff = SHOffset; + Ehdr.e_shnum = Sections.size() + 1; + Ehdr.e_shstrndx = SectionNames->Index; + } else { + Ehdr.e_shoff = 0; + Ehdr.e_shnum = 0; + Ehdr.e_shstrndx = 0; + } } template @@ -621,8 +627,19 @@ template void Object::writeSectionData(FileOutputBuffer &Out) const { - for (auto &Section : Sections) - Section->writeSection(Out); + // First write segment data that needs to be loaded + for (auto &Segment : this->Segments) { + if (Segment->Type == llvm::ELF::PT_LOAD) { + Segment->writeSegment(Out); + } + } + for (auto &Section : Sections) { + // Since we already write PT_LOAD segment data before this we don't need to + // write the data a second time. + if (Section->ParentSegment == nullptr || + Section->ParentSegment->Type != PT_LOAD) + Section->writeSection(Out); + } } template @@ -637,7 +654,20 @@ if (auto RelSec = dyn_cast(Sec.get())) return !ToRemove(*RelSec->getSection()); return true; - }); + }); + // The Object type maintains some references to certian special sections. We + // can remove those as well though and the output should still be sensible. + if (ToRemove(*SymbolTable)) + SymbolTable = nullptr; + if (ToRemove(*SectionNames)) { + // It only makes sense to remove the section header names if we also remove + // all sections. + if (Iter != Sections.begin()) + error("Cannot remove " + SectionNames->Name + + " because it is the section header string table and some sections" + " are being left in the section header table"); + SectionNames = nullptr; + } // Now make sure there are no remaining references to the sections that will // be removed. Sometimes it is impossible to remove a reference so we emit // an error here instead. @@ -737,30 +767,35 @@ template size_t ELFObject::totalSize() const { // We already have the section header offset so we can calculate the total // size by just adding up the size of each section header. + auto NullSectionSize = this->SectionNames != nullptr ? sizeof(Elf_Shdr) : 0; return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) + - sizeof(Elf_Shdr); + NullSectionSize; } template void ELFObject::write(FileOutputBuffer &Out) const { this->writeHeader(Out); this->writeProgramHeaders(Out); this->writeSectionData(Out); - this->writeSectionHeaders(Out); + if (this->SectionNames != nullptr) + this->writeSectionHeaders(Out); } template void ELFObject::finalize() { // Make sure we add the names of all the sections. - for (const auto &Section : this->Sections) { - this->SectionNames->addString(Section->Name); - } + if (this->SectionNames != nullptr) + for (const auto &Section : this->Sections) { + this->SectionNames->addString(Section->Name); + } // Make sure we add the names of all the symbols. - this->SymbolTable->addSymbolNames(); + if (this->SymbolTable != nullptr) + this->SymbolTable->addSymbolNames(); sortSections(); assignOffsets(); // Finalize SectionNames first so that we can assign name indexes. - this->SectionNames->finalize(); + if (this->SectionNames != nullptr) + this->SectionNames->finalize(); // Finally now that all offsets and indexes have been set we can finalize any // remaining issues. uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr); Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -56,10 +56,14 @@ cl::opt OutputFormat("O", cl::desc("set output format to one of the following:" "\n\tbinary")); -// TODO: make this a cl::list to support removing multiple sections cl::list ToRemove("remove-section", cl::desc("Remove a specific section")); -cl::alias ToRemoveA("R", cl::desc("Alias for -quiet"), cl::aliasopt(ToRemove)); +cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), + cl::aliasopt(ToRemove)); +cl::opt StripSections("strip-sections", + cl::desc("Remove all section headers")); + +typedef std::function SectionPred; void CopyBinary(const ELFObjectFile &ObjFile) { std::unique_ptr Buffer; @@ -70,12 +74,22 @@ Obj = llvm::make_unique>(ObjFile); else Obj = llvm::make_unique>(ObjFile); + + SectionPred RemovePred = [](const SectionBase &) { return false; }; + if (!ToRemove.empty()) { - Obj->removeSections([&](const SectionBase &Sec) { + RemovePred = [&](const SectionBase &Sec) { return std::find(std::begin(ToRemove), std::end(ToRemove), Sec.Name) != std::end(ToRemove); - }); + }; } + + if (StripSections) { + RemovePred = [](const SectionBase &) { return true; }; + } + + Obj->removeSections(RemovePred); + Obj->finalize(); ErrorOr> BufferOrErr = FileOutputBuffer::create(OutputFilename, Obj->totalSize(),