diff --git a/llvm/include/llvm/ObjCopy/ConfigManager.h b/llvm/include/llvm/ObjCopy/ConfigManager.h --- 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 @@ Expected getWasmConfig() const override; + Expected 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 --- a/llvm/include/llvm/ObjCopy/MultiFormatConfig.h +++ b/llvm/include/llvm/ObjCopy/MultiFormatConfig.h @@ -19,6 +19,7 @@ struct COFFConfig; struct MachOConfig; struct WasmConfig; +struct XCOFFConfig; class MultiFormatConfig { public: @@ -29,6 +30,7 @@ virtual Expected getCOFFConfig() const = 0; virtual Expected getMachOConfig() const = 0; virtual Expected getWasmConfig() const = 0; + virtual Expected getXCOFFConfig() const = 0; }; } // namespace objcopy diff --git a/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h b/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h --- a/llvm/include/llvm/ObjCopy/XCOFF/XCOFFConfig.h +++ 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 --- a/llvm/include/llvm/ObjCopy/XCOFF/XCOFFObjcopy.h +++ 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 --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -451,9 +451,6 @@ 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 const T *sectionHeaderTable() const; @@ -551,6 +548,8 @@ // Below here is the non-inherited interface. bool is64Bit() const; + Expected getRawData(const char *Start, uint64_t Size, + StringRef Name) const; const XCOFFAuxiliaryHeader32 *auxiliaryHeader32() const; const XCOFFAuxiliaryHeader64 *auxiliaryHeader64() const; @@ -562,6 +561,8 @@ 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 @@ Entry32 = reinterpret_cast(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 --- a/llvm/lib/ObjCopy/CMakeLists.txt +++ b/llvm/lib/ObjCopy/CMakeLists.txt @@ -13,6 +13,9 @@ 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\\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 @@ 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 @@ ${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 --- a/llvm/lib/ObjCopy/ConfigManager.cpp +++ b/llvm/lib/ObjCopy/ConfigManager.cpp @@ -66,5 +66,32 @@ return Wasm; } +Expected 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 --- 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 @@ return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(), *WasmConfig, *WasmBinary, Out); } + if (auto *XCOFFBinary = dyn_cast(&In)) { + Expected 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 --- a/llvm/lib/ObjCopy/XCOFF/XCOFFObjcopy.cpp +++ 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> 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 --- a/llvm/lib/ObjCopy/XCOFF/XCOFFObject.h +++ 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 + +namespace llvm { +namespace objcopy { +namespace xcoff { + +using namespace object; + +struct Section { + XCOFFSectionHeader32 SectionHeader; + ArrayRef Contents; + std::vector 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
Sections; + std::vector 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.h b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.h --- a/llvm/lib/ObjCopy/XCOFF/XCOFFReader.h +++ 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> 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/XCOFFReader.cpp b/llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp --- a/llvm/lib/ObjCopy/XCOFF/XCOFFReader.cpp +++ 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 Sections = XCOFFObj.sections32(); + for (const XCOFFSectionHeader32 &Sec : Sections) { + Section ReadSec; + // Section header. + ReadSec.SectionHeader = Sec; + DataRefImpl SectionDRI; + SectionDRI.p = reinterpret_cast(&Sec); + + // Section data. + if (Sec.SectionSize) { + Expected> ContentsRef = + XCOFFObj.getSectionContents(SectionDRI); + if (!ContentsRef) + return ContentsRef.takeError(); + ReadSec.Contents = ContentsRef.get(); + } + + // Relocations. + if (Sec.NumberOfRelocations) { + auto Relocations = + XCOFFObj.relocations(Sec); + if (!Relocations) + return Relocations.takeError(); + for (const XCOFFRelocation32 &Rel : Relocations.get()) + ReadSec.Relocations.push_back(Rel); + } + + Obj.Sections.push_back(ReadSec); + } + return Error::success(); +} + +Error XCOFFReader::readSymbols(Object &Obj) const { + std::vector 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( + SymbolDRI.p + XCOFF::SymbolTableEntrySize); + Expected RawAuxEntriesOrError = XCOFFObj.getRawData( + Start, + XCOFF::SymbolTableEntrySize * SymbolEntRef.getNumberOfAuxEntries(), + StringRef("symbol")); + if (!RawAuxEntriesOrError) + return RawAuxEntriesOrError.takeError(); + ReadSym.AuxSymbolEntries = RawAuxEntriesOrError.get(); + } + Obj.Symbols.push_back(ReadSym); + } + return Error::success(); +} + +Expected> XCOFFReader::create() const { + auto Obj = std::make_unique(); + // 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/XCOFFWriter.h b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h --- a/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.h +++ 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 +#include + +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 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/ObjCopy/XCOFF/XCOFFWriter.cpp b/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp --- a/llvm/lib/ObjCopy/XCOFF/XCOFFWriter.cpp +++ 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(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(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(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(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/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -709,6 +709,19 @@ return Binary::ID_XCOFF64 == getType(); } +Expected XCOFFObjectFile::getRawData(const char *Start, + uint64_t Size, + StringRef Name) const { + uintptr_t StartPtr = reinterpret_cast(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 --- a/llvm/test/tools/llvm-objcopy/XCOFF/basic-copy.test +++ 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 --- a/llvm/test/tools/llvm-objcopy/XCOFF/invalid-read.test +++ 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