diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -34,6 +34,8 @@ constexpr size_t SymbolTableEntrySize = 18; constexpr size_t RelocationSerializationSize32 = 10; constexpr size_t RelocationSerializationSize64 = 14; +constexpr size_t LineNumberEntrySize32 = 6; +constexpr size_t LineNumberEntrySize64 = 12; constexpr uint16_t RelocOverflow = 65535; constexpr uint8_t AllocRegNo = 31; 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 @@ -97,6 +97,22 @@ char Padding[4]; }; +struct LineNumberEntry32 { + union { + support::ubig32_t SymbolTableIndex; + support::ubig32_t AddressOfInstruction; + }; + support::ubig16_t LineNumber; +}; + +struct LineNumberEntry64 { + union { + support::ubig64_t SymbolTableIndex; + support::ubig64_t AddressOfInstruction; + }; + support::ubig32_t LineNumber; +}; + struct LoaderSectionHeader32 { support::ubig32_t Version; support::ubig32_t NumberOfSymTabEnt; @@ -296,14 +312,12 @@ class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; + const void *OptinalFileHeader = nullptr; const void *SectionHeaderTable = nullptr; 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; @@ -408,6 +422,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; @@ -436,6 +452,7 @@ Expected getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; uint16_t getOptionalHeaderSize() const; + const void *getOptionalHeaderStart() const { return OptinalFileHeader; } uint16_t getFlags() const; // Section header table related interfaces. @@ -455,6 +472,10 @@ template Expected> relocations(const Shdr &Sec) const; + // LineNumberInfo-related interfaces. + template + Expected> getLineNumberInfo(const Shdr &Sec) const; + // Loader section related interfaces. Expected getImportFileTable() const; @@ -531,6 +552,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/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -799,6 +799,29 @@ return ArrayRef(StartReloc, StartReloc + NumRelocEntries); } +template +Expected> +XCOFFObjectFile::getLineNumberInfo(const Shdr &Sec) const { + assert((sizeof(LineNO) == XCOFF::LineNumberEntrySize32 || + sizeof(LineNO) == XCOFF::LineNumberEntrySize64) && + "Line number entry structure is incorrect"); + + uint64_t NumberOfLineNumbers = Sec.NumberOfLineNumbers; + assert(NumberOfLineNumbers && + "Calling LineNumber interface with a non-LineNumber section."); + + uintptr_t LineNumberAddr = getWithOffset( + reinterpret_cast(FileHeader), Sec.FileOffsetToLineNumberInfo); + auto LineNumberInfoOrErr = + getObject(Data, reinterpret_cast(LineNumberAddr), + NumberOfLineNumbers * sizeof(LineNO)); + if (Error E = LineNumberInfoOrErr.takeError()) + return std::move(E); + + const LineNO *StartLineNum = LineNumberInfoOrErr.get(); + return ArrayRef(StartLineNum, StartLineNum + NumberOfLineNumbers); +} + Expected XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { // If there is a string table, then the buffer must contain at least 4 bytes @@ -886,10 +909,14 @@ if (Error E = FileHeaderOrErr.takeError()) return std::move(E); Obj->FileHeader = FileHeaderOrErr.get(); - CurOffset += Obj->getFileHeaderSize(); - // TODO FIXME we don't have support for an optional header yet, so just skip - // past it. + + // The auxiliary header immediately follows the file header. + auto OptinalFileHeaderOrErr = + getObject(Data, Base + CurOffset, Obj->getOptionalHeaderSize()); + if (Error E = OptinalFileHeaderOrErr.takeError()) + return std::move(E); + Obj->OptinalFileHeader = OptinalFileHeaderOrErr.get(); CurOffset += Obj->getOptionalHeaderSize(); // Parse the section header table if it is present. @@ -1053,6 +1080,15 @@ llvm::object::XCOFFRelocation32>( llvm::object::XCOFFSectionHeader32 const &) const; +template llvm::Expected> +llvm::object::XCOFFObjectFile::getLineNumberInfo< + llvm::object::XCOFFSectionHeader64, llvm::object::LineNumberEntry64>( + llvm::object::XCOFFSectionHeader64 const &) const; +template llvm::Expected> +llvm::object::XCOFFObjectFile::getLineNumberInfo< + llvm::object::XCOFFSectionHeader32, llvm::object::LineNumberEntry32>( + llvm::object::XCOFFSectionHeader32 const &) const; + bool doesXCOFFTracebackTableBegin(ArrayRef Bytes) { if (Bytes.size() < 4) return false; diff --git a/llvm/test/tools/llvm-objcopy/XCOFF/Inputs/basic32.o b/llvm/test/tools/llvm-objcopy/XCOFF/Inputs/basic32.o index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@&1 | FileCheck %s --check-prefix=ERROR1 + +# ERROR1: The end of the file was unexpectedly encountered + +--- !XCOFF +FileHeader: + MagicNumber: 0x01DF +Sections: + - SectionData: '00007400' + FileOffsetToData: 0x70 + +## Error2: failed to read relocations. +# RUN: yaml2obj %s --docnum=2 -o %t2 +# RUN: not llvm-objcopy %t2 %t2.out 2>&1 | FileCheck %s --check-prefix=ERROR2 + +# ERROR2: The end of the file was unexpectedly encountered + +--- !XCOFF +FileHeader: + MagicNumber: 0x01DF +Sections: + - NumberOfRelocations: 0x3 + Relocations: + - Address: 0xE + Symbol: 0x12 + Info: 0xF + Type: 0x3 + +## TODO: add test for failure to read line number info. diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -39,6 +39,9 @@ wasm/Reader.cpp wasm/Writer.cpp wasm/WasmObjcopy.cpp + XCOFF/Reader.cpp + XCOFF/Writer.cpp + XCOFF/XCOFFObjcopy.cpp DEPENDS ObjcopyOptsTableGen InstallNameToolOptsTableGen diff --git a/llvm/tools/llvm-objcopy/ConfigManager.h b/llvm/tools/llvm-objcopy/ConfigManager.h --- a/llvm/tools/llvm-objcopy/ConfigManager.h +++ b/llvm/tools/llvm-objcopy/ConfigManager.h @@ -15,6 +15,7 @@ #include "MachO/MachOConfig.h" #include "MultiFormatConfig.h" #include "wasm/WasmConfig.h" +#include "XCOFF/XCOFFConfig.h" #include "llvm/Support/Allocator.h" #include @@ -31,6 +32,7 @@ Expected getCOFFConfig() const override; Expected getMachOConfig() const override; Expected getWasmConfig() const override; + Expected getXCOFFConfig() const override; // All configs. CommonConfig Common; @@ -38,6 +40,7 @@ COFFConfig COFF; MachOConfig MachO; WasmConfig Wasm; + XCOFFConfig XCOFF; }; // Configuration for the overall invocation of this tool. When invoked as diff --git a/llvm/tools/llvm-objcopy/ConfigManager.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp --- a/llvm/tools/llvm-objcopy/ConfigManager.cpp +++ b/llvm/tools/llvm-objcopy/ConfigManager.cpp @@ -620,6 +620,33 @@ 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; +} + // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. diff --git a/llvm/tools/llvm-objcopy/MultiFormatConfig.h b/llvm/tools/llvm-objcopy/MultiFormatConfig.h --- a/llvm/tools/llvm-objcopy/MultiFormatConfig.h +++ b/llvm/tools/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/tools/llvm-objcopy/XCOFF/Object.h b/llvm/tools/llvm-objcopy/XCOFF/Object.h --- a/llvm/tools/llvm-objcopy/XCOFF/Object.h +++ b/llvm/tools/llvm-objcopy/XCOFF/Object.h @@ -0,0 +1,47 @@ +//===- Object.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_TOOLS_OBJCOPY_XCOFF_OBJECT_H +#define LLVM_TOOLS_OBJCOPY_XCOFF_OBJECT_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; + std::vector LineNumInfo; +}; + +struct Symbol { + XCOFFSymbolEntry32 Sym; + StringRef AuxSymbolEntries; // Not yet supported. Copy content directly. +}; + +struct Object { + XCOFFFileHeader32 FileHeader; + StringRef OptionalFileHeader; // Not yet supported. Copy content directly. + std::vector
Sections; + std::vector Symbols; + StringRef StringTable; +}; + +} // end namespace xcoff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_XCOFF_OBJECT_H diff --git a/llvm/tools/llvm-objcopy/XCOFF/Reader.h b/llvm/tools/llvm-objcopy/XCOFF/Reader.h --- a/llvm/tools/llvm-objcopy/XCOFF/Reader.h +++ b/llvm/tools/llvm-objcopy/XCOFF/Reader.h @@ -0,0 +1,35 @@ +//===- Reader.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_TOOLS_OBJCOPY_XCOFF_READER_H +#define LLVM_TOOLS_OBJCOPY_XCOFF_READER_H + +#include "Object.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_TOOLS_OBJCOPY_XCOFF_READER_H diff --git a/llvm/tools/llvm-objcopy/XCOFF/Reader.cpp b/llvm/tools/llvm-objcopy/XCOFF/Reader.cpp --- a/llvm/tools/llvm-objcopy/XCOFF/Reader.cpp +++ b/llvm/tools/llvm-objcopy/XCOFF/Reader.cpp @@ -0,0 +1,111 @@ +//===- Reader.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 "Reader.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); + } + + // Read line number info. + if (Sec.NumberOfLineNumbers) { + auto LineNumberInfo = + XCOFFObj.getLineNumberInfo( + Sec); + if (!LineNumberInfo) + return LineNumberInfo.takeError(); + for (const LineNumberEntry32 &LineNo : LineNumberInfo.get()) + ReadSec.LineNumInfo.push_back(LineNo); + } + + 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. + ReadSym.AuxSymbolEntries = StringRef( + reinterpret_cast(SymbolDRI.p + + XCOFF::SymbolTableEntrySize), + XCOFF::SymbolTableEntrySize * SymbolEntRef.getNumberOfAuxEntries()); + 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 = StringRef( + reinterpret_cast(XCOFFObj.getOptionalHeaderStart()), + XCOFFObj.getOptionalHeaderSize()); + + // Read each sectiondd. + 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); + + // Read the string table. + Obj->StringTable = XCOFFObj.getStringTable(); + return std::move(Obj); +} + +} // end namespace xcoff +} // end namespace objcopy +} // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/XCOFF/Writer.h b/llvm/tools/llvm-objcopy/XCOFF/Writer.h --- a/llvm/tools/llvm-objcopy/XCOFF/Writer.h +++ b/llvm/tools/llvm-objcopy/XCOFF/Writer.h @@ -0,0 +1,47 @@ +//===- Writer.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_TOOLS_OBJCOPY_XCOFF_WRITER_H +#define LLVM_TOOLS_OBJCOPY_XCOFF_WRITER_H + +#include "Object.h" +#include "llvm/Support/MemoryBuffer.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_TOOLS_OBJCOPY_XCOFF_WRITER_H diff --git a/llvm/tools/llvm-objcopy/XCOFF/Writer.cpp b/llvm/tools/llvm-objcopy/XCOFF/Writer.cpp --- a/llvm/tools/llvm-objcopy/XCOFF/Writer.cpp +++ b/llvm/tools/llvm-objcopy/XCOFF/Writer.cpp @@ -0,0 +1,137 @@ +//===- Writer.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 "Writer.h" +#include "llvm/Support/Errc.h" + +namespace llvm { +namespace objcopy { +namespace xcoff { + +using namespace object; + +void XCOFFWriter::finalizeHeaders() { + // File header. + FileSize += sizeof(XCOFFFileHeader32); + // Optional file header. + FileSize += Obj.OptionalFileHeader.size(); + // 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); + // Line number info. + FileSize += + Sec.SectionHeader.NumberOfLineNumbers * sizeof(LineNumberEntry32); + } +} + +void XCOFFWriter::finalizeSymbolStringTable() { + assert(Obj.FileHeader.SymbolTableOffset >= FileSize); + FileSize = Obj.FileHeader.SymbolTableOffset; + uint32_t NumOfSymEnt = 0; + // Symbols and auxiliary entries. + for (const Symbol &Sym : Obj.Symbols) + NumOfSymEnt += 1 + Sym.Sym.NumberOfAuxEntries; + FileSize += NumOfSymEnt * sizeof(XCOFFSymbolEntry32); + // 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 optinal header. + memcpy(Ptr, Obj.OptionalFileHeader.data(), Obj.OptionalFileHeader.size()); + Ptr += Obj.OptionalFileHeader.size(); + + // 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); + } + } + + // Write line number info. + for (const Section &Sec : Obj.Sections) { + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()) + + Sec.SectionHeader.FileOffsetToLineNumberInfo; + for (const LineNumberEntry32 &LineNumber : Sec.LineNumInfo) { + memcpy(Ptr, &LineNumber, sizeof(LineNumberEntry32)); + Ptr += sizeof(LineNumberEntry32); + } + } +} + +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, sizeof(XCOFFSymbolEntry32)); + Ptr += sizeof(XCOFFSymbolEntry32); + 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/tools/llvm-objcopy/XCOFF/XCOFFConfig.h b/llvm/tools/llvm-objcopy/XCOFF/XCOFFConfig.h --- a/llvm/tools/llvm-objcopy/XCOFF/XCOFFConfig.h +++ b/llvm/tools/llvm-objcopy/XCOFF/XCOFFConfig.h @@ -0,0 +1,21 @@ +//===- COFFConfig.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_TOOLS_LLVM_OBJCOPY_XCOFF_XCOFFCONFIG_H +#define LLVM_TOOLS_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_TOOLS_LLVM_OBJCOPY_XCOFF_XCOFFCONFIG_H diff --git a/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.h b/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.h --- a/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.h +++ b/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.h @@ -0,0 +1,32 @@ +//===- 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_TOOLS_LLVM_OBJCOPY_XCOFFOBJCOPY_H +#define LLVM_TOOLS_LLVM_OBJCOPY_XCOFFOBJCOPY_H + +namespace llvm { +class Error; +class raw_ostream; + +namespace object { +class XCOFFObjectFile; +} // end namespace object + +namespace objcopy { +struct CommonConfig; +struct XCOFFConfig; + +namespace xcoff { +Error executeObjcopyOnBinary(const CommonConfig &Config, const XCOFFConfig &, + object::XCOFFObjectFile &In, raw_ostream &Out); + +} // end namespace xcoff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_XCOFFOBJCOPY_H diff --git a/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.cpp b/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/XCOFF/XCOFFObjcopy.cpp +++ b/llvm/tools/llvm-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 "XCOFFObjcopy.h" +#include "CommonConfig.h" +#include "Object.h" +#include "Reader.h" +#include "Writer.h" +#include "XCOFFConfig.h" +#include "llvm/Support/Errc.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/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -17,6 +17,8 @@ #include "MachO/MachOObjcopy.h" #include "wasm/WasmConfig.h" #include "wasm/WasmObjcopy.h" +#include "XCOFF/XCOFFConfig.h" +#include "XCOFF/XCOFFObjcopy.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -33,6 +35,7 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/Wasm.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -202,6 +205,13 @@ return objcopy::wasm::executeObjcopyOnBinary(Config.getCommonConfig(), *WasmConfig, *WasmBinary, Out); + } else if (auto *XCOFFBinary = dyn_cast(&In)) { + Expected XCOFFConfig = Config.getXCOFFConfig(); + if (!XCOFFConfig) + return XCOFFConfig.takeError(); + + return xcoff::executeObjcopyOnBinary(Config.getCommonConfig(), *XCOFFConfig, + *XCOFFBinary, Out); } else return createStringError(object_error::invalid_file_type, "unsupported object file format");