| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |