[llvm] 61835d1 - [llvm-objcopy] Initial XCOFF32 support.
via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 28 02:00:15 PST 2022
Author: esmeyi
Date: 2022-02-28T04:59:46-05:00
New Revision: 61835d19a848ecd3530d9b86deb6b15f336ae6d6
URL: https://github.com/llvm/llvm-project/commit/61835d19a848ecd3530d9b86deb6b15f336ae6d6
DIFF: https://github.com/llvm/llvm-project/commit/61835d19a848ecd3530d9b86deb6b15f336ae6d6.diff
LOG: [llvm-objcopy] Initial XCOFF32 support.
Summary: This is an initial implementation of lvm-objcopy for XCOFF32.
Currently only supports simple copying, op-passthrough to follow.
Reviewed By: jhenderson, shchenz
Differential Revision: https://reviews.llvm.org/D97656
Added:
llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h
llvm/include/llvm/ObjCopy/XCOFF/XCOFFObjcopy.h
llvm/lib/ObjCopy/XCOFF/XCOFFObjcopy.cpp
llvm/lib/ObjCopy/XCOFF/XCOFFObject.h
llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp
llvm/lib/ObjCopy/XCOFF/XCOFFReader.h
llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp
llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h
llvm/test/tools/llvm-objcopy/XCOFF/basic-copy.test
llvm/test/tools/llvm-objcopy/XCOFF/invalid-read.test
Modified:
llvm/include/llvm/ObjCopy/ConfigManager.h
llvm/include/llvm/ObjCopy/MultiFormatConfig.h
llvm/include/llvm/Object/XCOFFObjectFile.h
llvm/lib/ObjCopy/CMakeLists.txt
llvm/lib/ObjCopy/ConfigManager.cpp
llvm/lib/ObjCopy/ObjCopy.cpp
llvm/lib/Object/XCOFFObjectFile.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ObjCopy/ConfigManager.h b/llvm/include/llvm/ObjCopy/ConfigManager.h
index 3aac601fca9a3..2962cf99b270d 100644
--- a/llvm/include/llvm/ObjCopy/ConfigManager.h
+++ b/llvm/include/llvm/ObjCopy/ConfigManager.h
@@ -15,6 +15,7 @@
#include "llvm/ObjCopy/MachO/MachOConfig.h"
#include "llvm/ObjCopy/MultiFormatConfig.h"
#include "llvm/ObjCopy/wasm/WasmConfig.h"
+#include "llvm/ObjCopy/XCOFF/XCOFFConfig.h"
namespace llvm {
namespace objcopy {
@@ -32,12 +33,15 @@ struct ConfigManager : public MultiFormatConfig {
Expected<const WasmConfig &> getWasmConfig() const override;
+ Expected<const XCOFFConfig &> getXCOFFConfig() const override;
+
// All configs.
CommonConfig Common;
ELFConfig ELF;
COFFConfig COFF;
MachOConfig MachO;
WasmConfig Wasm;
+ XCOFFConfig XCOFF;
};
} // namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/MultiFormatConfig.h b/llvm/include/llvm/ObjCopy/MultiFormatConfig.h
index 022751b6228bb..180f2f82a908b 100644
--- a/llvm/include/llvm/ObjCopy/MultiFormatConfig.h
+++ b/llvm/include/llvm/ObjCopy/MultiFormatConfig.h
@@ -19,6 +19,7 @@ struct ELFConfig;
struct COFFConfig;
struct MachOConfig;
struct WasmConfig;
+struct XCOFFConfig;
class MultiFormatConfig {
public:
@@ -29,6 +30,7 @@ class MultiFormatConfig {
virtual Expected<const COFFConfig &> getCOFFConfig() const = 0;
virtual Expected<const MachOConfig &> getMachOConfig() const = 0;
virtual Expected<const WasmConfig &> getWasmConfig() const = 0;
+ virtual Expected<const XCOFFConfig &> getXCOFFConfig() const = 0;
};
} // namespace objcopy
diff --git a/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h b/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h
new file mode 100644
index 0000000000000..adaeedc82b73b
--- /dev/null
+++ b/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h
@@ -0,0 +1,21 @@
+//===- XCOFFConfig.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCOPY_XCOFF_XCOFFCONFIG_H
+#define LLVM_OBJCOPY_XCOFF_XCOFFCONFIG_H
+
+namespace llvm {
+namespace objcopy {
+
+// XCOFF specific configuration for copying/stripping a single file.
+struct XCOFFConfig {};
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif // LLVM_OBJCOPY_XCOFF_XCOFFCONFIG_H
diff --git a/llvm/include/llvm/ObjCopy/XCOFF/XCOFFObjcopy.h b/llvm/include/llvm/ObjCopy/XCOFF/XCOFFObjcopy.h
new file mode 100644
index 0000000000000..9fc85cb39fa5b
--- /dev/null
+++ b/llvm/include/llvm/ObjCopy/XCOFF/XCOFFObjcopy.h
@@ -0,0 +1,35 @@
+//===- XCOFFObjcopy.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCOPY_XCOFF_XCOFFOBJCOPY_H
+#define LLVM_OBJCOPY_XCOFF_XCOFFOBJCOPY_H
+
+namespace llvm {
+class Error;
+class raw_ostream;
+
+namespace object {
+class XCOFFObjectFile;
+} // end namespace object
+
+namespace objcopy {
+struct CommonConfig;
+struct XCOFFConfig;
+
+namespace xcoff {
+/// Apply the transformations described by \p Config and \p XCOFFConfig
+/// to \p In and writes the result into \p Out.
+/// \returns any Error encountered whilst performing the operation.
+Error executeObjcopyOnBinary(const CommonConfig &Config, const XCOFFConfig &,
+ object::XCOFFObjectFile &In, raw_ostream &Out);
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_OBJCOPY_XCOFF_XCOFFOBJCOPY_H
diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h
index 5aad03b888fc2..585ead214380f 100644
--- a/llvm/include/llvm/Object/XCOFFObjectFile.h
+++ b/llvm/include/llvm/Object/XCOFFObjectFile.h
@@ -451,9 +451,6 @@ class XCOFFObjectFile : public ObjectFile {
const void *SymbolTblPtr = nullptr;
XCOFFStringTable StringTable = {0, nullptr};
- const XCOFFFileHeader32 *fileHeader32() const;
- const XCOFFFileHeader64 *fileHeader64() const;
-
const XCOFFSectionHeader32 *sectionHeaderTable32() const;
const XCOFFSectionHeader64 *sectionHeaderTable64() const;
template <typename T> const T *sectionHeaderTable() const;
@@ -551,6 +548,8 @@ class XCOFFObjectFile : public ObjectFile {
// Below here is the non-inherited interface.
bool is64Bit() const;
+ Expected<StringRef> getRawData(const char *Start, uint64_t Size,
+ StringRef Name) const;
const XCOFFAuxiliaryHeader32 *auxiliaryHeader32() const;
const XCOFFAuxiliaryHeader64 *auxiliaryHeader64() const;
@@ -562,6 +561,8 @@ class XCOFFObjectFile : public ObjectFile {
XCOFFSymbolRef toSymbolRef(DataRefImpl Ref) const;
// File header related interfaces.
+ const XCOFFFileHeader32 *fileHeader32() const;
+ const XCOFFFileHeader64 *fileHeader64() const;
uint16_t getMagic() const;
uint16_t getNumberOfSections() const;
int32_t getTimeStamp() const;
@@ -690,6 +691,9 @@ class XCOFFSymbolRef {
Entry32 = reinterpret_cast<const XCOFFSymbolEntry32 *>(SymEntDataRef.p);
}
+ const XCOFFSymbolEntry32 *getSymbol32() { return Entry32; }
+ const XCOFFSymbolEntry64 *getSymbol64() { return Entry64; }
+
uint64_t getValue() const { return Entry32 ? getValue32() : getValue64(); }
uint32_t getValue32() const { return Entry32->Value; }
diff --git a/llvm/lib/ObjCopy/CMakeLists.txt b/llvm/lib/ObjCopy/CMakeLists.txt
index 9b8365cd2f89c..54557f260f8d0 100644
--- a/llvm/lib/ObjCopy/CMakeLists.txt
+++ b/llvm/lib/ObjCopy/CMakeLists.txt
@@ -13,6 +13,9 @@ source_group("Header Files\\MachO" REGULAR_EXPRESSION
source_group("Header Files\\wasm" REGULAR_EXPRESSION
wasm/.*[.]h
)
+source_group("Header Files\\XCOFF" REGULAR_EXPRESSION
+ XCOFF/.*[.]h
+)
source_group("Source Files" REGULAR_EXPRESSION
.*[.]cpp
)
@@ -28,6 +31,9 @@ source_group("Source Files\\MachO" REGULAR_EXPRESSION
source_group("Source Files\\wasm" REGULAR_EXPRESSION
wasm/.*[.]cpp
)
+source_group("Source Files\\XCOFF" REGULAR_EXPRESSION
+ XCOFF/.*[.]cpp
+)
add_llvm_component_library(LLVMObjCopy
Archive.cpp
@@ -48,6 +54,9 @@ add_llvm_component_library(LLVMObjCopy
wasm/WasmReader.cpp
wasm/WasmWriter.cpp
wasm/WasmObjcopy.cpp
+ XCOFF/XCOFFObjcopy.cpp
+ XCOFF/XCOFFReader.cpp
+ XCOFF/XCOFFWriter.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCopy
@@ -55,10 +64,12 @@ add_llvm_component_library(LLVMObjCopy
${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCopy/ELF
${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCopy/MachO
${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCopy/wasm
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCopy/XCOFF
COFF
ELF
MachO
wasm
+ XCOFF
DEPENDS
intrinsics_gen
diff --git a/llvm/lib/ObjCopy/ConfigManager.cpp b/llvm/lib/ObjCopy/ConfigManager.cpp
index 6f6e1bd1a74f8..9d8883a15c0bf 100644
--- a/llvm/lib/ObjCopy/ConfigManager.cpp
+++ b/llvm/lib/ObjCopy/ConfigManager.cpp
@@ -66,5 +66,32 @@ Expected<const WasmConfig &> ConfigManager::getWasmConfig() const {
return Wasm;
}
+Expected<const XCOFFConfig &> ConfigManager::getXCOFFConfig() const {
+ if (!Common.AddGnuDebugLink.empty() || Common.ExtractPartition ||
+ !Common.SplitDWO.empty() || !Common.SymbolsPrefix.empty() ||
+ !Common.AllocSectionsPrefix.empty() ||
+ Common.DiscardMode != DiscardType::None || !Common.AddSection.empty() ||
+ !Common.DumpSection.empty() || !Common.SymbolsToAdd.empty() ||
+ !Common.KeepSection.empty() || !Common.OnlySection.empty() ||
+ !Common.ToRemove.empty() || !Common.SymbolsToGlobalize.empty() ||
+ !Common.SymbolsToKeep.empty() || !Common.SymbolsToLocalize.empty() ||
+ !Common.SymbolsToRemove.empty() ||
+ !Common.UnneededSymbolsToRemove.empty() ||
+ !Common.SymbolsToWeaken.empty() || !Common.SymbolsToKeepGlobal.empty() ||
+ !Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
+ !Common.SetSectionFlags.empty() || !Common.SymbolsToRename.empty() ||
+ Common.ExtractDWO || Common.ExtractMainPartition ||
+ Common.OnlyKeepDebug || Common.PreserveDates || Common.StripAllGNU ||
+ Common.StripDWO || Common.StripDebug || Common.StripNonAlloc ||
+ Common.StripSections || Common.Weaken || Common.StripUnneeded ||
+ Common.DecompressDebugSections) {
+ return createStringError(
+ llvm::errc::invalid_argument,
+ "no flags are supported yet, only basic copying is allowed");
+ }
+
+ return XCOFF;
+}
+
} // end namespace objcopy
} // end namespace llvm
diff --git a/llvm/lib/ObjCopy/ObjCopy.cpp b/llvm/lib/ObjCopy/ObjCopy.cpp
index a62f476567f56..16968d2022657 100644
--- a/llvm/lib/ObjCopy/ObjCopy.cpp
+++ b/llvm/lib/ObjCopy/ObjCopy.cpp
@@ -17,12 +17,15 @@
#include "llvm/ObjCopy/MultiFormatConfig.h"
#include "llvm/ObjCopy/wasm/WasmConfig.h"
#include "llvm/ObjCopy/wasm/WasmObjcopy.h"
+#include "llvm/ObjCopy/XCOFF/XCOFFConfig.h"
+#include "llvm/ObjCopy/XCOFF/XCOFFObjcopy.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/Wasm.h"
+#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/Support/SmallVectorMemoryBuffer.h"
namespace llvm {
@@ -71,6 +74,14 @@ Error executeObjcopyOnBinary(const MultiFormatConfig &Config,
return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(),
*WasmConfig, *WasmBinary, Out);
}
+ if (auto *XCOFFBinary = dyn_cast<object::XCOFFObjectFile>(&In)) {
+ Expected<const XCOFFConfig &> XCOFFConfig = Config.getXCOFFConfig();
+ if (!XCOFFConfig)
+ return XCOFFConfig.takeError();
+
+ return xcoff::executeObjcopyOnBinary(Config.getCommonConfig(), *XCOFFConfig,
+ *XCOFFBinary, Out);
+ }
return createStringError(object_error::invalid_file_type,
"unsupported object file format");
}
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFObjcopy.cpp b/llvm/lib/ObjCopy/XCOFF/XCOFFObjcopy.cpp
new file mode 100644
index 0000000000000..f6e29bd315cb1
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFObjcopy.cpp
@@ -0,0 +1,45 @@
+//===- XCOFFObjcopy.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjCopy/CommonConfig.h"
+#include "llvm/ObjCopy/XCOFF/XCOFFConfig.h"
+#include "llvm/ObjCopy/XCOFF/XCOFFObjcopy.h"
+#include "llvm/Support/Errc.h"
+#include "XCOFFObject.h"
+#include "XCOFFReader.h"
+#include "XCOFFWriter.h"
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+using namespace object;
+
+static Error handleArgs(const CommonConfig &Config, Object &Obj) {
+ return Error::success();
+}
+
+Error executeObjcopyOnBinary(const CommonConfig &Config, const XCOFFConfig &,
+ XCOFFObjectFile &In, raw_ostream &Out) {
+ XCOFFReader Reader(In);
+ Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
+ if (!ObjOrErr)
+ return createFileError(Config.InputFilename, ObjOrErr.takeError());
+ Object *Obj = ObjOrErr->get();
+ assert(Obj && "Unable to deserialize XCOFF object");
+ if (Error E = handleArgs(Config, *Obj))
+ return createFileError(Config.InputFilename, std::move(E));
+ XCOFFWriter Writer(*Obj, Out);
+ if (Error E = Writer.write())
+ return createFileError(Config.OutputFilename, std::move(E));
+ return Error::success();
+}
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFObject.h b/llvm/lib/ObjCopy/XCOFF/XCOFFObject.h
new file mode 100644
index 0000000000000..3c68b6d3878fc
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFObject.h
@@ -0,0 +1,48 @@
+//===- XCOFFObject.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_OBJCOPY_XCOFF_XCOFFOBJECT_H
+#define LLVM_LIB_OBJCOPY_XCOFF_XCOFFOBJECT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+using namespace object;
+
+struct Section {
+ XCOFFSectionHeader32 SectionHeader;
+ ArrayRef<uint8_t> Contents;
+ std::vector<XCOFFRelocation32> Relocations;
+};
+
+struct Symbol {
+ XCOFFSymbolEntry32 Sym;
+ // For now, each auxiliary symbol is only an opaque binary blob with no
+ // distinction.
+ StringRef AuxSymbolEntries;
+};
+
+struct Object {
+ XCOFFFileHeader32 FileHeader;
+ XCOFFAuxiliaryHeader32 OptionalFileHeader;
+ std::vector<Section> Sections;
+ std::vector<Symbol> Symbols;
+ StringRef StringTable;
+};
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_LIB_OBJCOPY_XCOFF_XCOFFOBJECT_H
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp
new file mode 100644
index 0000000000000..8ad3021a03428
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp
@@ -0,0 +1,101 @@
+//===- XCOFFReader.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "XCOFFReader.h"
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+using namespace object;
+
+Error XCOFFReader::readSections(Object &Obj) const {
+ ArrayRef<XCOFFSectionHeader32> Sections = XCOFFObj.sections32();
+ for (const XCOFFSectionHeader32 &Sec : Sections) {
+ Section ReadSec;
+ // Section header.
+ ReadSec.SectionHeader = Sec;
+ DataRefImpl SectionDRI;
+ SectionDRI.p = reinterpret_cast<uintptr_t>(&Sec);
+
+ // Section data.
+ if (Sec.SectionSize) {
+ Expected<ArrayRef<uint8_t>> ContentsRef =
+ XCOFFObj.getSectionContents(SectionDRI);
+ if (!ContentsRef)
+ return ContentsRef.takeError();
+ ReadSec.Contents = ContentsRef.get();
+ }
+
+ // Relocations.
+ if (Sec.NumberOfRelocations) {
+ auto Relocations =
+ XCOFFObj.relocations<XCOFFSectionHeader32, XCOFFRelocation32>(Sec);
+ if (!Relocations)
+ return Relocations.takeError();
+ for (const XCOFFRelocation32 &Rel : Relocations.get())
+ ReadSec.Relocations.push_back(Rel);
+ }
+
+ Obj.Sections.push_back(std::move(ReadSec));
+ }
+ return Error::success();
+}
+
+Error XCOFFReader::readSymbols(Object &Obj) const {
+ std::vector<Symbol> Symbols;
+ Symbols.reserve(XCOFFObj.getNumberOfSymbolTableEntries());
+ for (SymbolRef Sym : XCOFFObj.symbols()) {
+ Symbol ReadSym;
+ DataRefImpl SymbolDRI = Sym.getRawDataRefImpl();
+ XCOFFSymbolRef SymbolEntRef = XCOFFObj.toSymbolRef(SymbolDRI);
+ ReadSym.Sym = *SymbolEntRef.getSymbol32();
+ // Auxiliary entries.
+ if (SymbolEntRef.getNumberOfAuxEntries()) {
+ const char *Start = reinterpret_cast<const char *>(
+ SymbolDRI.p + XCOFF::SymbolTableEntrySize);
+ Expected<StringRef> RawAuxEntriesOrError = XCOFFObj.getRawData(
+ Start,
+ XCOFF::SymbolTableEntrySize * SymbolEntRef.getNumberOfAuxEntries(),
+ StringRef("symbol"));
+ if (!RawAuxEntriesOrError)
+ return RawAuxEntriesOrError.takeError();
+ ReadSym.AuxSymbolEntries = RawAuxEntriesOrError.get();
+ }
+ Obj.Symbols.push_back(std::move(ReadSym));
+ }
+ return Error::success();
+}
+
+Expected<std::unique_ptr<Object>> XCOFFReader::create() const {
+ auto Obj = std::make_unique<Object>();
+ // Only 32-bit supported now.
+ if (XCOFFObj.is64Bit())
+ return createStringError(object_error::invalid_file_type,
+ "64-bit XCOFF is not supported yet");
+ // Read the file header.
+ Obj->FileHeader = *XCOFFObj.fileHeader32();
+ // Read the optional header.
+ if (XCOFFObj.getOptionalHeaderSize())
+ Obj->OptionalFileHeader = *XCOFFObj.auxiliaryHeader32();
+ // Read each section.
+ Obj->Sections.reserve(XCOFFObj.getNumberOfSections());
+ if (Error E = readSections(*Obj))
+ return std::move(E);
+ // Read each symbol.
+ Obj->Symbols.reserve(XCOFFObj.getRawNumberOfSymbolTableEntries32());
+ if (Error E = readSymbols(*Obj))
+ return std::move(E);
+ // String table.
+ Obj->StringTable = XCOFFObj.getStringTable();
+ return std::move(Obj);
+}
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFReader.h b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.h
new file mode 100644
index 0000000000000..63a8d8579d37b
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.h
@@ -0,0 +1,35 @@
+//===- XCOFFReader.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_OBJCOPY_XCOFF_XCOFFREADER_H
+#define LLVM_LIB_OBJCOPY_XCOFF_XCOFFREADER_H
+
+#include "XCOFFObject.h"
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+using namespace object;
+
+class XCOFFReader {
+public:
+ explicit XCOFFReader(const XCOFFObjectFile &O) : XCOFFObj(O) {}
+ Expected<std::unique_ptr<Object>> create() const;
+
+private:
+ const XCOFFObjectFile &XCOFFObj;
+ Error readSections(Object &Obj) const;
+ Error readSymbols(Object &Obj) const;
+};
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_LIB_OBJCOPY_XCOFF_XCOFFREADER_H
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp
new file mode 100644
index 0000000000000..bae3128822e22
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp
@@ -0,0 +1,125 @@
+//===- XCOFFWriter.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Errc.h"
+#include "XCOFFWriter.h"
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+using namespace object;
+
+void XCOFFWriter::finalizeHeaders() {
+ // File header.
+ FileSize += sizeof(XCOFFFileHeader32);
+ // Optional file header.
+ FileSize += Obj.FileHeader.AuxHeaderSize;
+ // Section headers.
+ FileSize += sizeof(XCOFFSectionHeader32) * Obj.Sections.size();
+}
+
+void XCOFFWriter::finalizeSections() {
+ for (const Section &Sec : Obj.Sections) {
+ // Section data.
+ FileSize += Sec.Contents.size();
+ // Relocations.
+ FileSize +=
+ Sec.SectionHeader.NumberOfRelocations * sizeof(XCOFFRelocation32);
+ }
+}
+
+void XCOFFWriter::finalizeSymbolStringTable() {
+ assert(Obj.FileHeader.SymbolTableOffset >= FileSize);
+ FileSize = Obj.FileHeader.SymbolTableOffset;
+ // Symbols and auxiliary entries.
+ FileSize +=
+ Obj.FileHeader.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize;
+ // String table.
+ FileSize += Obj.StringTable.size();
+}
+
+void XCOFFWriter::finalize() {
+ FileSize = 0;
+ finalizeHeaders();
+ finalizeSections();
+ finalizeSymbolStringTable();
+}
+
+void XCOFFWriter::writeHeaders() {
+ // Write the file header.
+ uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
+ memcpy(Ptr, &Obj.FileHeader, sizeof(XCOFFFileHeader32));
+ Ptr += sizeof(XCOFFFileHeader32);
+
+ // Write the optional header.
+ if (Obj.FileHeader.AuxHeaderSize) {
+ memcpy(Ptr, &Obj.OptionalFileHeader, Obj.FileHeader.AuxHeaderSize);
+ Ptr += Obj.FileHeader.AuxHeaderSize;
+ }
+
+ // Write section headers.
+ for (const Section &Sec : Obj.Sections) {
+ memcpy(Ptr, &Sec.SectionHeader, sizeof(XCOFFSectionHeader32));
+ Ptr += sizeof(XCOFFSectionHeader32);
+ }
+}
+
+void XCOFFWriter::writeSections() {
+ // Write section data.
+ for (const Section &Sec : Obj.Sections) {
+ uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
+ Sec.SectionHeader.FileOffsetToRawData;
+ Ptr = std::copy(Sec.Contents.begin(), Sec.Contents.end(), Ptr);
+ }
+
+ // Write relocations.
+ for (const Section &Sec : Obj.Sections) {
+ uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
+ Sec.SectionHeader.FileOffsetToRelocationInfo;
+ for (const XCOFFRelocation32 &Rel : Sec.Relocations) {
+ memcpy(Ptr, &Rel, sizeof(XCOFFRelocation32));
+ Ptr += sizeof(XCOFFRelocation32);
+ }
+ }
+}
+
+void XCOFFWriter::writeSymbolStringTable() {
+ // Write symbols.
+ uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
+ Obj.FileHeader.SymbolTableOffset;
+ for (const Symbol &Sym : Obj.Symbols) {
+ memcpy(Ptr, &Sym.Sym, XCOFF::SymbolTableEntrySize);
+ Ptr += XCOFF::SymbolTableEntrySize;
+ // Auxiliary symbols.
+ memcpy(Ptr, Sym.AuxSymbolEntries.data(), Sym.AuxSymbolEntries.size());
+ Ptr += Sym.AuxSymbolEntries.size();
+ }
+ // Write the string table.
+ memcpy(Ptr, Obj.StringTable.data(), Obj.StringTable.size());
+ Ptr += Obj.StringTable.size();
+}
+
+Error XCOFFWriter::write() {
+ finalize();
+ Buf = WritableMemoryBuffer::getNewMemBuffer(FileSize);
+ if (!Buf)
+ return createStringError(errc::not_enough_memory,
+ "failed to allocate memory buffer of " +
+ Twine::utohexstr(FileSize) + " bytes");
+
+ writeHeaders();
+ writeSections();
+ writeSymbolStringTable();
+ Out.write(Buf->getBufferStart(), Buf->getBufferSize());
+ return Error::success();
+}
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h
new file mode 100644
index 0000000000000..54c7b5f3ccbe7
--- /dev/null
+++ b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h
@@ -0,0 +1,48 @@
+//===- XCOFFWriter.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_OBJCOPY_XCOFF_XCOFFWRITER_H
+#define LLVM_LIB_OBJCOPY_XCOFF_XCOFFWRITER_H
+
+#include "llvm/Support/MemoryBuffer.h"
+#include "XCOFFObject.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace xcoff {
+
+class XCOFFWriter {
+public:
+ virtual ~XCOFFWriter() {}
+ XCOFFWriter(Object &Obj, raw_ostream &Out) : Obj(Obj), Out(Out) {}
+ Error write();
+
+private:
+ Object &Obj;
+ raw_ostream &Out;
+ std::unique_ptr<WritableMemoryBuffer> Buf;
+ size_t FileSize;
+
+ void finalizeHeaders();
+ void finalizeSections();
+ void finalizeSymbolStringTable();
+ void finalize();
+
+ void writeHeaders();
+ void writeSections();
+ void writeSymbolStringTable();
+};
+
+} // end namespace xcoff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_LIB_OBJCOPY_XCOFF_XCOFFWRITER_H
diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index d9ecb0aff6bdc..5e699e97e052a 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -709,6 +709,19 @@ bool XCOFFObjectFile::is64Bit() const {
return Binary::ID_XCOFF64 == getType();
}
+Expected<StringRef> XCOFFObjectFile::getRawData(const char *Start,
+ uint64_t Size,
+ StringRef Name) const {
+ uintptr_t StartPtr = reinterpret_cast<uintptr_t>(Start);
+ // TODO: this path is untested.
+ if (Error E = Binary::checkOffset(Data, StartPtr, Size))
+ return createError(toString(std::move(E)) + ": " + Name.data() +
+ " data with offset 0x" + Twine::utohexstr(StartPtr) +
+ " and size 0x" + Twine::utohexstr(Size) +
+ " goes past the end of the file");
+ return StringRef(Start, Size);
+}
+
uint16_t XCOFFObjectFile::getMagic() const {
return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
}
diff --git a/llvm/test/tools/llvm-objcopy/XCOFF/basic-copy.test b/llvm/test/tools/llvm-objcopy/XCOFF/basic-copy.test
new file mode 100644
index 0000000000000..467efd9b5bbf9
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/XCOFF/basic-copy.test
@@ -0,0 +1,31 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objcopy %t %t.out
+# RUN: cmp %t %t.out
+
+--- !XCOFF
+FileHeader:
+ MagicNumber: 0x1DF
+AuxiliaryHeader:
+ Magic: 0x10B
+Sections:
+ - Name: .text
+ Flags: [ STYP_TEXT ]
+ SectionData: "123456"
+ - Name: .data
+ Flags: [ STYP_DATA ]
+ SectionData: "067891"
+ Relocations:
+ - Address: 0x3A
+ Type: 0x02
+Symbols:
+ - Name: aux_fcn_csect
+ StorageClass: C_EXT
+ Type: 0x20
+ AuxEntries:
+ - Type: AUX_FCN
+ - Type: AUX_CSECT
+ - Name: aux_stat
+ StorageClass: C_STAT
+ AuxEntries:
+ - Type: AUX_STAT
+...
diff --git a/llvm/test/tools/llvm-objcopy/XCOFF/invalid-read.test b/llvm/test/tools/llvm-objcopy/XCOFF/invalid-read.test
new file mode 100644
index 0000000000000..1df63406a4136
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/XCOFF/invalid-read.test
@@ -0,0 +1,47 @@
+## Check that llvm-objcopy reports a suitable error when it
+## encounters invalid input during reading.
+
+## Failed to read section data.
+# RUN: yaml2obj %s --docnum=1 -o %t1
+# RUN: not llvm-objcopy %t1 %t1.out 2>&1 | FileCheck %s -DFILE=%t1 --check-prefix=ERROR1
+
+# ERROR1: error: '[[FILE]]': The end of the file was unexpectedly encountered: section data with offset 0x70 and size 0x4 goes past the end of the file
+
+--- !XCOFF
+FileHeader:
+ MagicNumber: 0x01DF
+Sections:
+ - SectionData: '00007400'
+ FileOffsetToData: 0x70
+
+## Failed to read relocations.
+# RUN: yaml2obj %s --docnum=2 -o %t2
+# RUN: not llvm-objcopy %t2 %t2.out 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=ERROR2
+
+# ERROR2: error: '[[FILE]]': The end of the file was unexpectedly encountered: relocations with offset 0x3c and size 0x1e go past the end of the file
+
+--- !XCOFF
+FileHeader:
+ MagicNumber: 0x01DF
+Sections:
+ - NumberOfRelocations: 0x3
+ Relocations:
+ - Address: 0xE
+ Symbol: 0x12
+ Info: 0xF
+ Type: 0x3
+
+## Failed to read the symbols.
+# RUN: yaml2obj %s --docnum=3 -o %t3
+# RUN: not llvm-objcopy %t3 %t3.out 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=ERROR3
+
+# ERROR3: error: '[[FILE]]': The end of the file was unexpectedly encountered: symbol table with offset 0x15 and size 0x24 goes past the end of the file
+
+--- !XCOFF
+FileHeader:
+ MagicNumber: 0x01DF
+ OffsetToSymbolTable: 0x15
+Symbols:
+ - Name: foo
+ AuxEntries:
+ - Type: AUX_CSECT
More information about the llvm-commits
mailing list