summaryrefslogtreecommitdiff
path: root/tools/llvm-objcopy
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-objcopy')
-rw-r--r--tools/llvm-objcopy/CMakeLists.txt4
-rw-r--r--tools/llvm-objcopy/Object.cpp20
-rw-r--r--tools/llvm-objcopy/Object.h1
-rw-r--r--tools/llvm-objcopy/llvm-objcopy.cpp81
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) {