diff options
Diffstat (limited to 'tools/llvm-objcopy')
-rw-r--r-- | tools/llvm-objcopy/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tools/llvm-objcopy/Object.cpp | 20 | ||||
-rw-r--r-- | tools/llvm-objcopy/Object.h | 1 | ||||
-rw-r--r-- | tools/llvm-objcopy/llvm-objcopy.cpp | 81 |
4 files changed, 88 insertions, 18 deletions
diff --git a/tools/llvm-objcopy/CMakeLists.txt b/tools/llvm-objcopy/CMakeLists.txt index 18cc2075345d..05aa727ab9d8 100644 --- a/tools/llvm-objcopy/CMakeLists.txt +++ b/tools/llvm-objcopy/CMakeLists.txt @@ -7,3 +7,7 @@ add_llvm_tool(llvm-objcopy llvm-objcopy.cpp Object.cpp ) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objcopy llvm-objcopy) +endif() diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index 22ae47f1cace..5f9864d9cc04 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -685,6 +685,19 @@ template <class ELFT> void ELFObject<ELFT>::sortSections() { CompareSections); } +static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) { + // Calculate Diff such that (Offset + Diff) & -Align == Addr & -Align. + if (Align == 0) + Align = 1; + auto Diff = + static_cast<int64_t>(Addr % Align) - static_cast<int64_t>(Offset % Align); + // We only want to add to Offset, however, so if Diff < 0 we can add Align and + // (Offset + Diff) & -Align == Addr & -Align will still hold. + if (Diff < 0) + Diff += Align; + return Offset + Diff; +} + template <class ELFT> void ELFObject<ELFT>::assignOffsets() { // We need a temporary list of segments that has a special order to it // so that we know that anytime ->ParentSegment is set that segment has @@ -728,7 +741,7 @@ template <class ELFT> void ELFObject<ELFT>::assignOffsets() { Segment->Offset = Parent->Offset + Segment->OriginalOffset - Parent->OriginalOffset; } else { - Offset = alignTo(Offset, Segment->Align == 0 ? 1 : Segment->Align); + Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); Segment->Offset = Offset; } Offset = std::max(Offset, Segment->Offset + Segment->FileSize); @@ -829,8 +842,9 @@ template <class ELFT> void BinaryObject<ELFT>::finalize() { uint64_t Offset = 0; for (auto &Segment : this->Segments) { - if (Segment->Type == PT_LOAD && Segment->firstSection() != nullptr) { - Offset = alignTo(Offset, Segment->Align); + if (Segment->Type == llvm::ELF::PT_LOAD && + Segment->firstSection() != nullptr) { + Offset = alignToAddr(Offset, Segment->VAddr, Segment->Align); Segment->Offset = Offset; Offset += Segment->FileSize; } diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 9c77f5900ce2..f12e6da7d21c 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -368,6 +368,7 @@ public: Object(const object::ELFObjectFile<ELFT> &Obj); virtual ~Object() = default; + const SectionBase *getSectionHeaderStrTab() const { return SectionNames; } void removeSections(std::function<bool(const SectionBase &)> ToRemove); virtual size_t totalSize() const = 0; virtual void finalize() = 0; diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp index f3e9c7750a64..c923f902db82 100644 --- a/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/tools/llvm-objcopy/llvm-objcopy.cpp @@ -83,12 +83,63 @@ static cl::alias ToRemoveA("R", cl::desc("Alias for remove-section"), cl::aliasopt(ToRemove)); static cl::opt<bool> StripSections("strip-sections", cl::desc("Remove all section headers")); +static cl::opt<bool> + StripDWO("strip-dwo", cl::desc("remove all DWARF .dwo sections from file")); +static cl::opt<bool> ExtractDWO( + "extract-dwo", + cl::desc("remove all sections that are not DWARF .dwo sections from file")); +static cl::opt<std::string> + SplitDWO("split-dwo", + cl::desc("equivalent to extract-dwo on the input file to " + "<dwo-file>, then strip-dwo on the input file"), + cl::value_desc("dwo-file")); using SectionPred = std::function<bool(const SectionBase &Sec)>; -void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { +bool IsDWOSection(const SectionBase &Sec) { + return Sec.Name.endswith(".dwo"); +} + +template <class ELFT> +bool OnlyKeepDWOPred(const Object<ELFT> &Obj, const SectionBase &Sec) { + // We can't remove the section header string table. + if (&Sec == Obj.getSectionHeaderStrTab()) + return false; + // Short of keeping the string table we want to keep everything that is a DWO + // section and remove everything else. + return !IsDWOSection(Sec); +} + +template <class ELFT> +void WriteObjectFile(const Object<ELFT> &Obj, StringRef File) { std::unique_ptr<FileOutputBuffer> Buffer; + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + FileOutputBuffer::create(File, Obj.totalSize(), + FileOutputBuffer::F_executable); + if (BufferOrErr.takeError()) + error("failed to open " + OutputFilename); + else + Buffer = std::move(*BufferOrErr); + Obj.write(*Buffer); + if (auto E = Buffer->commit()) + reportError(File, errorToErrorCode(std::move(E))); +} + +template <class ELFT> +void SplitDWOToFile(const ELFObjectFile<ELFT> &ObjFile, StringRef File) { + // Construct a second output file for the DWO sections. + ELFObject<ELFT> DWOFile(ObjFile); + + DWOFile.removeSections([&](const SectionBase &Sec) { + return OnlyKeepDWOPred<ELFT>(DWOFile, Sec); + }); + DWOFile.finalize(); + WriteObjectFile(DWOFile, File); +} + +void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { std::unique_ptr<Object<ELF64LE>> Obj; + if (!OutputFormat.empty() && OutputFormat != "binary") error("invalid output format '" + OutputFormat + "'"); if (!OutputFormat.empty() && OutputFormat == "binary") @@ -96,6 +147,9 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { else Obj = llvm::make_unique<ELFObject<ELF64LE>>(ObjFile); + if (!SplitDWO.empty()) + SplitDWOToFile<ELF64LE>(ObjFile, SplitDWO.getValue()); + SectionPred RemovePred = [](const SectionBase &) { return false; }; if (!ToRemove.empty()) { @@ -105,6 +159,16 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { }; } + if (StripDWO || !SplitDWO.empty()) + RemovePred = [RemovePred](const SectionBase &Sec) { + return IsDWOSection(Sec) || RemovePred(Sec); + }; + + if (ExtractDWO) + RemovePred = [RemovePred, &Obj](const SectionBase &Sec) { + return OnlyKeepDWOPred(*Obj, Sec) || RemovePred(Sec); + }; + if (StripSections) { RemovePred = [RemovePred](const SectionBase &Sec) { return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0; @@ -113,21 +177,8 @@ void CopyBinary(const ELFObjectFile<ELF64LE> &ObjFile) { } Obj->removeSections(RemovePred); - Obj->finalize(); - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(OutputFilename, Obj->totalSize(), - FileOutputBuffer::F_executable); - if (BufferOrErr.getError()) - error("failed to open " + OutputFilename); - else - Buffer = std::move(*BufferOrErr); - std::error_code EC; - if (EC) - report_fatal_error(EC.message()); - Obj->write(*Buffer); - if (auto EC = Buffer->commit()) - reportError(OutputFilename, EC); + WriteObjectFile(*Obj, OutputFilename.getValue()); } int main(int argc, char **argv) { |