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 @@ -270,9 +270,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; @@ -366,6 +363,8 @@ // Below here is the non-inherited interface. bool is64Bit() const; + const XCOFFFileHeader32 *fileHeader32() const; + const XCOFFFileHeader64 *fileHeader64() const; const void *getPointerToSymbolTable() const { return SymbolTblPtr; } @@ -474,6 +473,8 @@ class XCOFFSymbolRef { public: enum { NAME_IN_STR_TBL_MAGIC = 0x0 }; + const XCOFFSymbolEntry32 *Entry32 = nullptr; + const XCOFFSymbolEntry64 *Entry64 = nullptr; XCOFFSymbolRef(DataRefImpl SymEntDataRef, const XCOFFObjectFile *OwningObjectPtr) @@ -530,8 +531,6 @@ private: const XCOFFObjectFile *OwningObjectPtr; - const XCOFFSymbolEntry32 *Entry32 = nullptr; - const XCOFFSymbolEntry64 *Entry64 = nullptr; }; class TBVectorExt { 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,37 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy %t %t2 +# RUN: cmp %t %t2 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .text + Flags: 0x20 + SectionData: "9061FFF8808200008064000038630001906400008061FFF8386300019061FFF88061FFF88082000480840000888400007C6322149061FFF88061FFF84E8000200000000000092040800001010000000000000040000466756E310000600000007C0802A693E1FFFC900100089421FFB07C3F0B7838600000907F004880620008907F0044808300003884000190830000806300004BFFFF6D60000000807F0044806300004BFFFF5D60000000382100508001000883E1FFFC7C0803A64E8000200000000000092261800100010000006000046D61696E1F006162636400000000" + - Name: .data + Flags: 0x40 + SectionData: "00000000000000FC0000000000000060000000FC00000000000000D800000108000000F800000000" + Relocations: + - Address: 0x3A + Type: 0x02 + - Flags: 0x80 +Symbols: + - Name: .file + Section: N_DEBUG + Type: 0x3 + StorageClass: C_FILE + NumberOfAuxEntries: 1 + - Name: iiiiiiiii + Value: 0x0 + Section: N_UNDEF + Type: 0x0 + StorageClass: C_EXT + NumberOfAuxEntries: 0 + - Name: .text + Value: 0x0 + Section: .text + Type: 0x0 + StorageClass: C_HIDEXT + NumberOfAuxEntries: 0 +... 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 @@ -40,6 +40,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/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,44 @@ +//===- 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; +}; + +struct Symbol { + XCOFFSymbolEntry32 Sym; + StringRef SymbolName; +}; + +struct Object { + XCOFFFileHeader32 FileHeader; + std::vector
Sections; + std::vector Symbols; +}; + +} // 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,88 @@ +//===- 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; + // Read section header. + ReadSec.SectionHeader = Sec; + + // Read section data. + if (Sec.SectionSize) { + DataRefImpl SectionDRI; + SectionDRI.p = reinterpret_cast(&Sec); + Expected> ContentsRef = + XCOFFObj.getSectionContents(SectionDRI); + if (!ContentsRef) + return ContentsRef.takeError(); + ReadSec.Contents = ContentsRef.get(); + } + + // Read relocations. + if (Sec.NumberOfRelocations) { + Expected> Relocations = + XCOFFObj.relocations(Sec); + if (!Relocations) + return Relocations.takeError(); + for (XCOFFRelocation32 Reloc : Relocations.get()) + ReadSec.Relocations.push_back(Reloc); + } + Obj.Sections.push_back(ReadSec); + } + return Error::success(); +} + +Error XCOFFReader::readSymbols(Object &Obj) const { + std::vector Symbols; + Symbols.reserve(XCOFFObj.getRawNumberOfSymbolTableEntries32()); + for (const SymbolRef &S : XCOFFObj.symbols()) { + Symbols.push_back(Symbol()); + Symbol &Sym = Symbols.back(); + DataRefImpl SymbolDRI = S.getRawDataRefImpl(); + const XCOFFSymbolRef SymbolEntRef = XCOFFObj.toSymbolRef(SymbolDRI); + Sym.Sym = *SymbolEntRef.Entry32; + Expected SymNameOrError = XCOFFObj.getSymbolName(SymbolDRI); + if (!SymNameOrError) + return SymNameOrError.takeError(); + Sym.SymbolName = SymNameOrError.get(); + Obj.Symbols.push_back(Sym); + } + 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 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); + 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,42 @@ +//===- 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/MC/StringTableBuilder.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), Strings(StringTableBuilder::XCOFF) {} + Error write(); + +private: + Object &Obj; + raw_ostream &Out; + std::unique_ptr Buf; + StringTableBuilder Strings; + size_t finalizeStringTable(); + size_t finalize(); +}; + +} // 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,108 @@ +//===- 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; + +size_t XCOFFWriter::finalize() { + size_t FileSize = 0; + // Finalize file headers. + FileSize += XCOFF::FileHeaderSize32; + Obj.FileHeader.NumberOfSections = Obj.Sections.size(); + Obj.FileHeader.NumberOfSymTableEntries = Obj.Symbols.size(); + + // Finalize sections. + FileSize += XCOFF::SectionHeaderSize32 * Obj.Sections.size(); + for (Section &Sec : Obj.Sections) { + // Section data. + if (Sec.Contents.size()) { + Sec.SectionHeader.FileOffsetToRawData = FileSize; + FileSize += Sec.Contents.size(); + } + // Relocations. + Sec.SectionHeader.NumberOfRelocations = Sec.Relocations.size(); + if (Sec.Relocations.size()) + FileSize += Sec.Relocations.size() * XCOFF::RelocationSerializationSize32; + } + + // Finalize symbols. + Obj.FileHeader.SymbolTableOffset = FileSize; + uint32_t NumOfSymEnt = 0; + for (Symbol &Sym : Obj.Symbols) + NumOfSymEnt += 1 + Sym.Sym.NumberOfAuxEntries; + Obj.FileHeader.NumberOfSymTableEntries = NumOfSymEnt; + FileSize += NumOfSymEnt * XCOFF::SymbolTableEntrySize; + + // Finalize string table. + for (const Symbol &Sym : Obj.Symbols) + if (Sym.SymbolName.size() > XCOFF::NameSize) + Strings.add(Sym.SymbolName); + Strings.finalize(); + FileSize += Strings.getSize(); + return FileSize; +} + +Error XCOFFWriter::write() { + size_t TotalSize = finalize(); + Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize); + if (!Buf) + return createStringError(errc::not_enough_memory, + "failed to allocate memory buffer of " + + Twine::utohexstr(TotalSize) + " bytes"); + + // Write the file header. + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()); + memcpy(Ptr, &Obj.FileHeader, sizeof(XCOFFFileHeader32)); + Ptr += sizeof(XCOFFFileHeader32); + + // Write section headers. + for (Section &Sec : Obj.Sections) { + memcpy(Ptr, &Sec.SectionHeader, sizeof(XCOFFSectionHeader32)); + Ptr += sizeof(XCOFFSectionHeader32); + } + + // Write section data. + for (Section &Sec : Obj.Sections) { + Ptr = reinterpret_cast(Buf->getBufferStart()) + + Sec.SectionHeader.FileOffsetToRawData; + Ptr = std::copy(Sec.Contents.begin(), Sec.Contents.end(), Ptr); + } + + // Write relocations. + for (Section &Sec : Obj.Sections) { + Ptr = reinterpret_cast(Buf->getBufferStart()) + + Sec.SectionHeader.FileOffsetToRelocationInfo; + for (XCOFFRelocation32 &Relo : Sec.Relocations) { + memcpy(Ptr, &Relo, sizeof(XCOFFRelocation32)); + Ptr += sizeof(XCOFFRelocation32); + } + } + + // Write symbols. + Ptr = reinterpret_cast(Buf->getBufferStart()) + + Obj.FileHeader.SymbolTableOffset; + for (Symbol &Sym : Obj.Symbols) { + memcpy(Ptr, &Sym.Sym, XCOFF::SymbolTableEntrySize); + Ptr += XCOFF::SymbolTableEntrySize * (1 + Sym.Sym.NumberOfAuxEntries); + } + // Write the string table. + Strings.write(Ptr); + Ptr += Strings.getSize(); + 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/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,31 @@ +//===- 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 CopyConfig; + +namespace xcoff { +Error executeObjcopyOnBinary(const CopyConfig &Config, + object::XCOFFObjectFile &In, raw_ostream &Out); + +} // end namespace xcoff +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_LLVM_OBJCOPY_XCOFFOBJCOPY_H \ No newline at end of file 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,71 @@ +//===- 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 "CopyConfig.h" +#include "Object.h" +#include "Reader.h" +#include "Writer.h" +#include "llvm/Support/Errc.h" + +namespace llvm { +namespace objcopy { +namespace xcoff { + +using namespace object; + +static Error handleArgs(const CopyConfig &Config, Object &Obj) { + if (!Config.AddGnuDebugLink.empty() || Config.ExtractPartition || + !Config.SplitDWO.empty() || !Config.SymbolsPrefix.empty() || + !Config.AllocSectionsPrefix.empty() || + Config.DiscardMode != DiscardType::None || Config.NewSymbolVisibility || + !Config.AddSection.empty() || !Config.DumpSection.empty() || + !Config.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() || + !Config.RPathToPrepend.empty() || !Config.RPathsToUpdate.empty() || + !Config.InstallNamesToUpdate.empty() || !Config.RPathsToRemove.empty() || + !Config.KeepSection.empty() || !Config.OnlySection.empty() || + !Config.ToRemove.empty() || !Config.SymbolsToGlobalize.empty() || + !Config.SymbolsToKeep.empty() || !Config.SymbolsToLocalize.empty() || + !Config.SymbolsToRemove.empty() || + !Config.UnneededSymbolsToRemove.empty() || + !Config.SymbolsToWeaken.empty() || !Config.SymbolsToKeepGlobal.empty() || + !Config.SectionsToRename.empty() || !Config.SetSectionAlignment.empty() || + !Config.SetSectionFlags.empty() || !Config.SymbolsToRename.empty() || + Config.AllowBrokenLinks || Config.ExtractDWO || Config.KeepFileSymbols || + Config.ExtractMainPartition || Config.KeepUndefined || + Config.OnlyKeepDebug || Config.LocalizeHidden || Config.PreserveDates || + Config.StripAllGNU || Config.StripDWO || Config.StripDebug || + Config.StripNonAlloc || Config.StripSections || Config.Weaken || + Config.StripSwiftSymbols || Config.StripUnneeded || + Config.DecompressDebugSections) { + return createStringError( + llvm::errc::invalid_argument, + "no flags are supported yet, only basic copying is allowed"); + } + return Error::success(); +} + +Error executeObjcopyOnBinary(const CopyConfig &Config, 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 @@ -12,6 +12,7 @@ #include "ELF/ELFObjcopy.h" #include "MachO/MachOObjcopy.h" #include "wasm/WasmObjcopy.h" +#include "XCOFF/XCOFFObjcopy.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -28,6 +29,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" @@ -179,6 +181,8 @@ Config, *MachOUniversalBinary, Out); else if (auto *WasmBinary = dyn_cast(&In)) return objcopy::wasm::executeObjcopyOnBinary(Config, *WasmBinary, Out); + else if (auto *XCOFFBinary = dyn_cast(&In)) + return xcoff::executeObjcopyOnBinary(Config, *XCOFFBinary, Out); else return createStringError(object_error::invalid_file_type, "unsupported object file format");