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 @@ -336,6 +336,7 @@ uint16_t getMagic() const; uint16_t getNumberOfSections() const; int32_t getTimeStamp() const; + const XCOFFFileHeader32 *getFileHeader32() const; // Symbol table offset and entry count are handled differently between // XCOFF32 and XCOFF64. @@ -363,6 +364,8 @@ int32_t getSectionFlags(DataRefImpl Sec) const; Expected getSectionByNum(int16_t Num) const; + Expected> + getSectionContents(const XCOFFSectionHeader32 &Sec) const; void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; 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 @@ -471,6 +471,10 @@ return Binary::ID_XCOFF64 == getType(); } +const XCOFFFileHeader32 *XCOFFObjectFile::getFileHeader32() const { + return fileHeader32(); +} + uint16_t XCOFFObjectFile::getMagic() const { return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; } @@ -626,6 +630,20 @@ TablePtr + getNumberOfSections()); } +Expected> +XCOFFObjectFile::getSectionContents(const XCOFFSectionHeader32 &Sec) const { + uint32_t OffsetToRaw = Sec.FileOffsetToRawData; + if (OffsetToRaw == 0) + return ArrayRef(); + + const uint8_t *ContentStart = base() + OffsetToRaw; + uint64_t SectionSize = Sec.SectionSize; + if (checkOffset(Data, reinterpret_cast(ContentStart), SectionSize)) + return make_error(); + + return makeArrayRef(ContentStart, SectionSize); +} + // In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO // section header contains the actual count of relocation entries in the s_paddr // field. STYP_OVRFLO headers contain the section index of their corresponding 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,57 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy %t %t2 +# RUN: cmp %t %t2 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .text + Relocations: + - Address: 0xE + Symbol: 0x12 + Info: 0xF + Type: 0x3 + - Address: 0x1A + Symbol: 0x12 + Info: 0xF + Type: 0x3 + - Name: .data + Address: 0x60 + SectionData: '00000000000000740000000000000000000000600000000000000000' + Relocations: + - Address: 0x60 + Symbol: 0x8 + Info: 0x1F + Type: 0x0 +Symbols: + - Name: .file + Section: N_DEBUG + Type: 0x3 + StorageClass: C_FILE + NumberOfAuxEntries: 0x1 + FileAuxEntry: + FileName: test.c + Type: XFT_FN + - Name: i + Value: 0x0 + Section: N_UNDEF + Type: 0x0 + StorageClass: C_EXT + NumberOfAuxEntries: 0x1 + CsectAuxEntry: + SectionLen: 0 + StorageMappingClass: XMC_UA + StabInfoIndex: 0 + StabSectNum: 0 + - Name: .text + Value: 0x0 + Section: .text + Type: 0x0 + StorageClass: C_HIDEXT + NumberOfAuxEntries: 0x1 + CsectAuxEntry: + SectionLen: 96 + SymbolAlignmentAndType: 17 + StorageMappingClass: XMC_PR +... 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 @@ -41,6 +41,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,39 @@ +//===- 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 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,75 @@ +//===- 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 (XCOFFSectionHeader32 Sec : Sections) { + Section ReadSec; + // Read section header. + ReadSec.SectionHeader = Sec; + // Read section data. + if (Sec.SectionSize) { + Expected> ContentsRef = + XCOFFObj.getSectionContents(Sec); + 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 { + for (const SymbolRef &S : XCOFFObj.symbols()) { + DataRefImpl SymbolDRI = S.getRawDataRefImpl(); + const XCOFFSymbolEntry *SymbolEntPtr = XCOFFObj.toSymbolEntry(SymbolDRI); + Obj.Symbols.push_back(*SymbolEntPtr); + } + 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.getFileHeader32(); + // 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,37 @@ +//===- 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 "Buffer.h" +#include "Object.h" +#include +#include + +namespace llvm { +namespace objcopy { +namespace xcoff { + +class XCOFFWriter { +public: + virtual ~XCOFFWriter() {} + XCOFFWriter(Object &Obj, Buffer &Buf) : Obj(Obj), Buf(Buf) {} + Error write(); + +private: + Object &Obj; + Buffer &Buf; + 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,81 @@ +//===- 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" + +namespace llvm { +namespace objcopy { +namespace xcoff { + +using namespace object; + +size_t XCOFFWriter::finalize() { + size_t FileSize = 0; + // Finalize file headers. + FileSize += sizeof(XCOFFFileHeader32); + Obj.FileHeader.NumberOfSections = Obj.Sections.size(); + Obj.FileHeader.NumberOfSymTableEntries = Obj.Symbols.size(); + // Finalize sections. + FileSize += sizeof(XCOFFSectionHeader32) * Obj.Sections.size(); + for (Section &Sec : Obj.Sections) { + // Section data. + if (Sec.SectionHeader.SectionSize) + FileSize += Sec.SectionHeader.SectionSize; + // Relocations. + Sec.SectionHeader.NumberOfRelocations = Sec.Relocations.size(); + if (Sec.Relocations.size()) + FileSize += Sec.Relocations.size() * sizeof(XCOFFRelocation32); + } + // Finalize symbols. + Obj.FileHeader.SymbolTableOffset = FileSize; + uint32_t NumOfSymEnt = 0; + for (XCOFFSymbolEntry &Sym : Obj.Symbols) + NumOfSymEnt += 1 + Sym.NumberOfAuxEntries; + Obj.FileHeader.NumberOfSymTableEntries = NumOfSymEnt; + FileSize += NumOfSymEnt * sizeof(XCOFFSymbolEntry); + return FileSize; +} + +Error XCOFFWriter::write() { + size_t FileSize = finalize(); + if (Error E = Buf.allocate(FileSize)) + return E; + // Write the file header. + uint8_t *Ptr = 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 = Buf.getBufferStart() + Sec.SectionHeader.FileOffsetToRawData; + Ptr = std::copy(Sec.Contents.begin(), Sec.Contents.end(), Ptr); + } + // Write relocations. + for (Section &Sec : Obj.Sections) { + Ptr = Buf.getBufferStart() + Sec.SectionHeader.FileOffsetToRelocationInfo; + for (XCOFFRelocation32 &Relo : Sec.Relocations) { + memcpy(Ptr, &Relo, sizeof(XCOFFRelocation32)); + Ptr += sizeof(XCOFFRelocation32); + } + } + // Write symbols. + Ptr = Buf.getBufferStart() + Obj.FileHeader.SymbolTableOffset; + for (XCOFFSymbolEntry &Sym : Obj.Symbols) { + memcpy(Ptr, &Sym, sizeof(XCOFFSymbolEntry)); + Ptr += sizeof(XCOFFSymbolEntry) * (1 + Sym.NumberOfAuxEntries); + } + return Buf.commit(); +} + +} // 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; + +namespace object { +class XCOFFObjectFile; +} // end namespace object + +namespace objcopy { +struct CopyConfig; +class Buffer; + +namespace xcoff { +Error executeObjcopyOnBinary(const CopyConfig &Config, + object::XCOFFObjectFile &In, Buffer &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,62 @@ +//===- 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.SymbolsToAdd.empty() || !Config.RPathToAdd.empty() || + !Config.OnlySection.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.ToRemove.empty() || !Config.DumpSection.empty() || + !Config.AddSection.empty()) { + 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, + Buffer &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" @@ -27,6 +28,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" @@ -175,6 +177,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");