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 @@ -228,7 +228,7 @@ uint8_t Pad[10]; }; // 32-bit XCOFF file only. -struct XCOFFRelocation32 { +template struct XCOFFRelocation { // Masks for packing/unpacking the r_rsize field of relocations. // The msb is used to indicate if the bits being relocated are signed or @@ -244,7 +244,7 @@ static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f; public: - support::ubig32_t VirtualAddress; + AddressType VirtualAddress; support::ubig32_t SymbolIndex; // Packed field, see XR_* masks for details of packing. @@ -260,6 +260,12 @@ uint8_t getRelocatedLength() const; }; +extern template struct XCOFFRelocation; +extern template struct XCOFFRelocation; + +struct XCOFFRelocation32 : XCOFFRelocation {}; +struct XCOFFRelocation64 : XCOFFRelocation {}; + class XCOFFSymbolRef; class XCOFFObjectFile : public ObjectFile { @@ -275,6 +281,7 @@ const XCOFFSectionHeader32 *sectionHeaderTable32() const; const XCOFFSectionHeader64 *sectionHeaderTable64() const; + template const T *sectionHeaderTable() const; size_t getFileHeaderSize() const; size_t getSectionHeaderSize() const; @@ -415,11 +422,12 @@ void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; // Relocation-related interfaces. + template Expected - getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const; + getNumberOfRelocationEntries(const XCOFFSectionHeader &Sec) const; - Expected> - relocations(const XCOFFSectionHeader32 &) const; + template + Expected> relocations(const Shdr &Sec) const; // This function returns string table entry. Expected getStringTableEntry(uint32_t Offset) const; @@ -572,6 +580,7 @@ Optional ExtensionTable; XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err); + public: /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes. /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an 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 @@ -69,15 +69,18 @@ return getSectionType() & SectionFlagsReservedMask; } -bool XCOFFRelocation32::isRelocationSigned() const { +template +bool XCOFFRelocation::isRelocationSigned() const { return Info & XR_SIGN_INDICATOR_MASK; } -bool XCOFFRelocation32::isFixupIndicated() const { +template +bool XCOFFRelocation::isFixupIndicated() const { return Info & XR_FIXUP_INDICATOR_MASK; } -uint8_t XCOFFRelocation32::getRelocatedLength() const { +template +uint8_t XCOFFRelocation::getRelocatedLength() const { // The relocation encodes the bit length being relocated minus 1. Add back // the 1 to get the actual length being relocated. return (Info & XR_BIASED_LENGTH_MASK) + 1; @@ -146,6 +149,10 @@ return static_cast(FileHeader); } +template const T *XCOFFObjectFile::sectionHeaderTable() const { + return static_cast(SectionHeaderTable); +} + const XCOFFSectionHeader32 * XCOFFObjectFile::sectionHeaderTable32() const { assert(!is64Bit() && "32-bit interface called on 64-bit object file."); @@ -329,61 +336,112 @@ } relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { - if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); - const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); - auto RelocationsOrErr = relocations(*SectionEntPtr); - if (Error E = RelocationsOrErr.takeError()) - return relocation_iterator(RelocationRef()); DataRefImpl Ret; - Ret.p = reinterpret_cast(&*RelocationsOrErr.get().begin()); + if (is64Bit()) { + const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); + auto RelocationsOrErr = + relocations(*SectionEntPtr); + if (Error E = RelocationsOrErr.takeError()) { + // TODO: report the error up the stack. + consumeError(std::move(E)); + return relocation_iterator(RelocationRef()); + } + Ret.p = reinterpret_cast(&*RelocationsOrErr.get().begin()); + } else { + const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); + auto RelocationsOrErr = + relocations(*SectionEntPtr); + if (Error E = RelocationsOrErr.takeError()) { + // TODO: report the error up the stack. + consumeError(std::move(E)); + return relocation_iterator(RelocationRef()); + } + Ret.p = reinterpret_cast(&*RelocationsOrErr.get().begin()); + } return relocation_iterator(RelocationRef(Ret, this)); } relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { - if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); - const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); - auto RelocationsOrErr = relocations(*SectionEntPtr); - if (Error E = RelocationsOrErr.takeError()) - return relocation_iterator(RelocationRef()); DataRefImpl Ret; - Ret.p = reinterpret_cast(&*RelocationsOrErr.get().end()); + if (is64Bit()) { + const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec); + auto RelocationsOrErr = + relocations(*SectionEntPtr); + if (Error E = RelocationsOrErr.takeError()) { + // TODO: report the error up the stack. + consumeError(std::move(E)); + return relocation_iterator(RelocationRef()); + } + Ret.p = reinterpret_cast(&*RelocationsOrErr.get().end()); + } else { + const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); + auto RelocationsOrErr = + relocations(*SectionEntPtr); + if (Error E = RelocationsOrErr.takeError()) { + // TODO: report the error up the stack. + consumeError(std::move(E)); + return relocation_iterator(RelocationRef()); + } + Ret.p = reinterpret_cast(&*RelocationsOrErr.get().end()); + } return relocation_iterator(RelocationRef(Ret, this)); } void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { - Rel.p = reinterpret_cast(viewAs(Rel.p) + 1); + if (is64Bit()) + Rel.p = reinterpret_cast(viewAs(Rel.p) + 1); + else + Rel.p = reinterpret_cast(viewAs(Rel.p) + 1); } uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { - if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); - const XCOFFRelocation32 *Reloc = viewAs(Rel.p); - const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32(); - const uint32_t RelocAddress = Reloc->VirtualAddress; - const uint16_t NumberOfSections = getNumberOfSections(); - for (uint16_t i = 0; i < NumberOfSections; ++i) { - // Find which section this relocation is belonging to, and get the - // relocation offset relative to the start of the section. - if (Sec32->VirtualAddress <= RelocAddress && - RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) { - return RelocAddress - Sec32->VirtualAddress; + if (is64Bit()) { + const XCOFFRelocation64 *Reloc = viewAs(Rel.p); + const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64(); + const uint64_t RelocAddress = Reloc->VirtualAddress; + const uint16_t NumberOfSections = getNumberOfSections(); + for (uint16_t I = 0; I < NumberOfSections; ++I) { + // Find which section this relocation belongs to, and get the + // relocation offset relative to the start of the section. + if (Sec64->VirtualAddress <= RelocAddress && + RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) { + return RelocAddress - Sec64->VirtualAddress; + } + ++Sec64; + } + } else { + const XCOFFRelocation32 *Reloc = viewAs(Rel.p); + const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32(); + const uint32_t RelocAddress = Reloc->VirtualAddress; + const uint16_t NumberOfSections = getNumberOfSections(); + for (uint16_t I = 0; I < NumberOfSections; ++I) { + // Find which section this relocation belongs to, and get the + // relocation offset relative to the start of the section. + if (Sec32->VirtualAddress <= RelocAddress && + RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) { + return RelocAddress - Sec32->VirtualAddress; + } + ++Sec32; } - ++Sec32; } return InvalidRelocOffset; } symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { - if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); - const XCOFFRelocation32 *Reloc = viewAs(Rel.p); - const uint32_t Index = Reloc->SymbolIndex; - - if (Index >= getLogicalNumberOfSymbolTableEntries32()) - return symbol_end(); - + uint32_t Index; + if (is64Bit()) { + const XCOFFRelocation64 *Reloc = viewAs(Rel.p); + Index = Reloc->SymbolIndex; + + if (Index >= getNumberOfSymbolTableEntries64()) + return symbol_end(); + } else { + const XCOFFRelocation32 *Reloc = viewAs(Rel.p); + Index = Reloc->SymbolIndex; + + if (Index >= getLogicalNumberOfSymbolTableEntries32()) + return symbol_end(); + } DataRefImpl SymDRI; SymDRI.p = getSymbolEntryAddressByIndex(Index); return symbol_iterator(SymbolRef(SymDRI, this)); @@ -391,16 +449,20 @@ uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); + return viewAs(Rel.p)->Type; return viewAs(Rel.p)->Type; } void XCOFFObjectFile::getRelocationTypeName( DataRefImpl Rel, SmallVectorImpl &Result) const { - if (is64Bit()) - report_fatal_error("64-bit support not implemented yet"); - const XCOFFRelocation32 *Reloc = viewAs(Rel.p); - StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type); + StringRef Res; + if (is64Bit()) { + const XCOFFRelocation64 *Reloc = viewAs(Rel.p); + Res = XCOFF::getRelocationTypeString(Reloc->Type); + } else { + const XCOFFRelocation32 *Reloc = viewAs(Rel.p); + Res = XCOFF::getRelocationTypeString(Reloc->Type); + } Result.append(Res.begin(), Res.end()); } @@ -661,13 +723,16 @@ // section header contains the actual count of relocation entries in the s_paddr // field. STYP_OVRFLO headers contain the section index of their corresponding // sections as their raw "NumberOfRelocations" field value. -Expected XCOFFObjectFile::getLogicalNumberOfRelocationEntries( - const XCOFFSectionHeader32 &Sec) const { - - uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1; +template +Expected XCOFFObjectFile::getNumberOfRelocationEntries( + const XCOFFSectionHeader &Sec) const { + const T &Section = static_cast(Sec); + if (is64Bit()) + return Section.NumberOfRelocations; - if (Sec.NumberOfRelocations < XCOFF::RelocOverflow) - return Sec.NumberOfRelocations; + uint16_t SectionIndex = &Section - sectionHeaderTable() + 1; + if (Section.NumberOfRelocations < XCOFF::RelocOverflow) + return Section.NumberOfRelocations; for (const auto &Sec : sections32()) { if (Sec.Flags == XCOFF::STYP_OVRFLO && Sec.NumberOfRelocations == SectionIndex) @@ -676,27 +741,27 @@ return errorCodeToError(object_error::parse_failed); } -Expected> -XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const { +template +Expected> XCOFFObjectFile::relocations(const Shdr &Sec) const { uintptr_t RelocAddr = getWithOffset(reinterpret_cast(FileHeader), Sec.FileOffsetToRelocationInfo); - auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec); + auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec); if (Error E = NumRelocEntriesOrErr.takeError()) return std::move(E); uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); - - static_assert( - sizeof(XCOFFRelocation32) == XCOFF::RelocationSerializationSize32, ""); + static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 || + sizeof(Reloc) == XCOFF::RelocationSerializationSize32), + "Relocation structure is incorrect"); auto RelocationOrErr = - getObject(Data, reinterpret_cast(RelocAddr), - NumRelocEntries * sizeof(XCOFFRelocation32)); + getObject(Data, reinterpret_cast(RelocAddr), + NumRelocEntries * sizeof(Reloc)); if (Error E = RelocationOrErr.takeError()) return std::move(E); - const XCOFFRelocation32 *StartReloc = RelocationOrErr.get(); + const Reloc *StartReloc = RelocationOrErr.get(); - return ArrayRef(StartReloc, StartReloc + NumRelocEntries); + return ArrayRef(StartReloc, StartReloc + NumRelocEntries); } Expected @@ -900,6 +965,18 @@ template struct XCOFFSectionHeader; template struct XCOFFSectionHeader; +template struct XCOFFRelocation; +template struct XCOFFRelocation; + +template llvm::Expected> +llvm::object::XCOFFObjectFile::relocations( + llvm::object::XCOFFSectionHeader64 const &) const; +template llvm::Expected> +llvm::object::XCOFFObjectFile::relocations( + llvm::object::XCOFFSectionHeader32 const &) const; + bool doesXCOFFTracebackTableBegin(ArrayRef Bytes) { if (Bytes.size() < 4) return false; diff --git a/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbol-description64.test b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbol-description64.test --- a/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbol-description64.test +++ b/llvm/test/tools/llvm-objdump/XCOFF/disassemble-symbol-description64.test @@ -6,9 +6,8 @@ # RUN: llvm-objdump -D --symbol-description %p/Inputs/xcoff-section-headers64.o | \ # RUN: FileCheck --check-prefixes=COMMON,DESC %s -# RUN: not --crash llvm-objdump -D -r --symbol-description %p/Inputs/xcoff-section-headers64.o 2>&1 | \ -# RUN: FileCheck --check-prefix=ERROR %s -# ERROR: 64-bit support not implemented yet +# RUN: llvm-objdump -D -r --symbol-description %p/Inputs/xcoff-section-headers64.o | \ +# RUN: FileCheck --check-prefixes=COMMON,DESC,RELOC,COMMON-RELOC %s ## xcoff-section-headers64.o Compiled with IBM XL C/C++ for AIX, V16.1.0 ## compiler command: xlc -q64 -qtls -o xcoff-section-headers64.o -c test.c @@ -29,6 +28,7 @@ PLAIN: 0000000000000000 <.func>: DESC: 0000000000000000 (idx: 6) .func: COMMON-NEXT: 0: e8 62 00 08 ld 3, 8(2) +RELOC-NEXT: 00000002: R_TOC (idx: 16) a[TC] COMMON-NEXT: 4: e8 63 00 02 lwa 3, 0(3) COMMON-NEXT: 8: 4e 80 00 20 blr COMMON-NEXT: c: 00 00 00 00 @@ -44,31 +44,40 @@ PLAIN: 0000000000000080 : DESC: 0000000000000080 (idx: 12) func[TC]: COMMON-NEXT: 80: 00 00 00 00 +RELOC-NEXT: 00000080: R_POS (idx: 10) func[DS] COMMON-NEXT: 84: 00 00 00 a8 COMMON-EMPTY: PLAIN: 0000000000000088 : DESC: 0000000000000088 (idx: 16) a[TC]: COMMON-NEXT: 88: 00 00 00 00 +RELOC-NEXT: 00000088: R_POS (idx: 14) a[RW] COMMON-NEXT: 8c: 00 00 00 c8 COMMON-EMPTY: PLAIN: 0000000000000090 : DESC: 0000000000000090 (idx: 20) b[TC]: COMMON-NEXT: 90: 00 00 00 00 +RELOC-NEXT: 00000090: R_POS (idx: 18) b[RW] COMMON-NEXT: 94: 00 00 00 c0 COMMON-EMPTY: PLAIN: 0000000000000098 : DESC: 0000000000000098 (idx: 24) c[TC]: COMMON-NEXT: 98: 00 00 00 00 +RELOC-NEXT: 00000098: R_TLS (idx: 22) c[UL] COMMON-NEXT: 9c: 00 00 00 08 COMMON-EMPTY: PLAIN: 00000000000000a0 : DESC: 00000000000000a0 (idx: 28) d[TC]: -COMMON-NEXT: ... -COMMON-EMPTY: +COMMON-RELOC-NEXT: a0: 00 00 00 00 +RELOC-NEXT: 000000a0: R_TLS (idx: 26) d[TL] +COMMON-RELOC-NEXT: a4: 00 00 00 00 PLAIN: 00000000000000a8 : DESC: 00000000000000a8 (idx: 10) func[DS]: -COMMON-NEXT: ... -COMMON-NEXT: b4: 00 00 00 80 +COMMON-RELOC-NEXT: a8: 00 00 00 00 +RELOC-NEXT: 000000a8: R_POS (idx: 6) .func +COMMON-RELOC-NEXT: ac: 00 00 00 00 +COMMON-RELOC-NEXT: b0: 00 00 00 00 +RELOC-NEXT: 000000b0: R_POS (idx: 8) TOC[TC0] +COMMON: b4: 00 00 00 80 COMMON-NEXT: ... COMMON-EMPTY: PLAIN: 00000000000000c0 : diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -44,7 +44,8 @@ void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef); void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); void printSymbol(const SymbolRef &); - void printRelocations(ArrayRef Sections); + template + void printRelocations(ArrayRef Sections); const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -105,9 +106,9 @@ void XCOFFDumper::printRelocations() { if (Obj.is64Bit()) - llvm_unreachable("64-bit relocation output not implemented!"); + printRelocations(Obj.sections64()); else - printRelocations(Obj.sections32()); + printRelocations(Obj.sections32()); } static const EnumEntry RelocationTypeNameclass[] = { @@ -122,31 +123,32 @@ #undef ECase }; -void XCOFFDumper::printRelocations(ArrayRef Sections) { +template +void XCOFFDumper::printRelocations(ArrayRef Sections) { if (!opts::ExpandRelocs) report_fatal_error("Unexpanded relocation output not implemented."); ListScope LS(W, "Relocations"); uint16_t Index = 0; - for (const auto &Sec : Sections) { + for (const Shdr &Sec : Sections) { ++Index; // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) continue; - auto ErrOrRelocations = Obj.relocations(Sec); + Expected> ErrOrRelocations = Obj.relocations(Sec); if (Error E = ErrOrRelocations.takeError()) { reportUniqueWarning(std::move(E)); continue; } - auto Relocations = *ErrOrRelocations; + const ArrayRef Relocations = *ErrOrRelocations; if (Relocations.empty()) continue; W.startLine() << "Section (index: " << Index << ") " << Sec.getName() << " {\n"; - for (auto Reloc : Relocations) { + for (const RelTy Reloc : Relocations) { Expected ErrOrSymbolName = Obj.getSymbolNameByIndex(Reloc.SymbolIndex); if (Error E = ErrOrSymbolName.takeError()) {