Index: llvm/include/llvm/BinaryFormat/XCOFF.h =================================================================== --- llvm/include/llvm/BinaryFormat/XCOFF.h +++ llvm/include/llvm/BinaryFormat/XCOFF.h @@ -148,6 +148,40 @@ XTY_CM = 3 ///< Common csect definition. For uninitialized storage. }; +// Relocation types, defined in `/usr/include/reloc.h`. +enum RelocationType : uint8_t { + R_POS = 0x00, + R_RL = 0x0c, + R_RLA = 0x0d, + + R_NEG = 0x01, + R_REL = 0x02, + + R_TOC = 0x03, + R_TRL = 0x12, + R_TRLA = 0x13, + + R_GL = 0x05, + R_TCL = 0x06, + + R_REF = 0x0f, + + R_BA = 0x08, + R_BR = 0x0a, + R_RBA = 0x18, + R_RBR = 0x1a, + + R_TLS = 0x20, + R_TLS_IE = 0x21, + R_TLS_LD = 0x22, + R_TLS_LE = 0x23, + R_TLSM = 0x24, + R_TLSML = 0x25, + + R_TOCU = 0x30, + R_TOCL = 0x31 +}; + struct FileHeader32 { uint16_t Magic; uint16_t NumberOfSections; Index: llvm/include/llvm/Object/XCOFFObjectFile.h =================================================================== --- llvm/include/llvm/Object/XCOFFObjectFile.h +++ llvm/include/llvm/Object/XCOFFObjectFile.h @@ -144,6 +144,43 @@ uint8_t Pad[10]; }; +struct XCOFFRelocation32 { + support::ubig32_t VirtualAddress; + support::ubig32_t SymbolIndex; + + // Packed field, see XR_* masks for details of packing. + uint8_t Info; + + XCOFF::RelocationType Type; +}; + +// Masks for packing/unpacking the r_rsize field of relocations. +// The msb is used to indicate if the bits being relocated are signed or +// unsigned. +static constexpr uint8_t XR_SIGN_INDICATOR_MASK = 0x80; +// The 2nd msb is used to indicate that the binder has replaced/modified the +// original instuction. +static constexpr uint8_t XR_FIXUP_INDICATOR_MASK = 0x40; +// The remaining bits specify the bit length of the relocatable reference +// minus one. +static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f; + +template bool isRelocationSigned(T Reloc) { + return Reloc.Info & XR_SIGN_INDICATOR_MASK; +} +// If the Fixup bit is set, it indicates that the linker has modified +// the instruction the relocation refers to. +template bool isFixupIndicated(T Reloc) { + return Reloc.Info & XR_FIXUP_INDICATOR_MASK; +} + +// Returns the number of bits being relocated. +template uint8_t getRelocatedLength(T Reloc) { + // The relocation encodes the bit length being relocated minus 1. Add back + // the 1 to get the actual length being relocated. + return (Reloc.Info & XR_BIASED_LENGTH_MASK) + 1; +} + class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; @@ -231,7 +268,6 @@ uint64_t getRelocationType(DataRefImpl Rel) const override; void getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl &Result) const override; - section_iterator section_begin() const override; section_iterator section_end() const override; uint8_t getBytesInAddress() const override; @@ -273,6 +309,7 @@ uint32_t getNumberOfSymbolTableEntries64() const; uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; + Expected getSymbolNameByIndex(uint32_t SymbolTableIndex) const; Expected getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; uint16_t getOptionalHeaderSize() const; @@ -286,6 +323,8 @@ Expected getSectionByNum(int16_t Num) const; void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; + // Relocation related interfaces. + ArrayRef relocations(const XCOFFSectionHeader32 &) const; }; // XCOFFObjectFile class XCOFFSymbolRef { Index: llvm/lib/Object/XCOFFObjectFile.cpp =================================================================== --- llvm/lib/Object/XCOFFObjectFile.cpp +++ llvm/lib/Object/XCOFFObjectFile.cpp @@ -17,10 +17,7 @@ namespace llvm { namespace object { -enum { - FUNCTION_SYM = 0x20, - SYM_TYPE_MASK = 0x07 -}; +enum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 }; // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer // 'M'. Returns a pointer to the underlying object on success. @@ -494,6 +491,19 @@ XCOFF::SymbolTableEntrySize; } +Expected +XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { + if (is64Bit()) + report_fatal_error("64-bit symbol table support not implemented yet."); + + if (Index >= getLogicalNumberOfSymbolTableEntries32()) + return errorCodeToError(object_error::invalid_symbol_index); + + DataRefImpl SymDRI; + SymDRI.p = reinterpret_cast(getPointerToSymbolTable() + Index); + return getSymbolName(SymDRI); +} + uint16_t XCOFFObjectFile::getFlags() const { return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; } @@ -640,6 +650,16 @@ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries; } +ArrayRef +XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const { + uintptr_t RelocAddr = getWithOffset(reinterpret_cast(FileHeader), + Sec.FileOffsetToRelocationInfo); + XCOFFRelocation32 *StartReloc = + reinterpret_cast(RelocAddr); + return ArrayRef(StartReloc, + StartReloc + Sec.NumberOfRelocations); +} + const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const { assert(!OwningObjectPtr->is64Bit() && "32-bit interface called on 64-bit object file."); Index: llvm/test/tools/llvm-readobj/xcoff-basic.test =================================================================== --- llvm/test/tools/llvm-readobj/xcoff-basic.test +++ llvm/test/tools/llvm-readobj/xcoff-basic.test @@ -10,6 +10,9 @@ # RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic-neg-sym-count.o | \ # RUN: FileCheck --check-prefix=NEGSYMCOUNT %s +# RUN: llvm-readobj --relocs --expand-relocs %p/Inputs/xcoff-basic.o | \ +# RUN: FileCheck --check-prefix=RELOCSEXP %s + # FILEHEADER: File: {{.*}}xcoff-basic.o # FILEHEADER-NEXT: Format: aixcoff-rs6000 # FILEHEADER-NEXT: Arch: powerpc @@ -81,3 +84,61 @@ # xcoff-basic-neg-sym-count.o was stripped using the 'strip' utility, and # manually edited to have a negative symbol table entry count. +# RELOCSEXP: File: {{.*}}xcoff-basic.o +# RELOCSEXP-NEXT: Format: aixcoff-rs6000 +# RELOCSEXP-NEXT: Arch: powerpc +# RELOCSEXP-NEXT: AddressSize: 32bit +# RELOCSEXP-NEXT: Relocations [ +# RELOCSEXP-NEXT: Section (1) .text { +# RELOCSEXP-NEXT: Relocation { +# RELOCSEXP-NEXT: Virtual Address: 0x2 +# RELOCSEXP-NEXT: Symbol: a (85) +# RELOCSEXP-NEXT: IsSigned: Yes +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 16 +# RELOCSEXP-NEXT: Type: R_TOC (0x3) +# RELOCSEXP-NEXT: } + +# RELOCSEXP: Virtual Address: 0x50 +# RELOCSEXP-NEXT: Symbol: .__tls_get_addr (118) +# RELOCSEXP-NEXT: IsSigned: Yes +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 26 +# RELOCSEXP-NEXT: Type: R_RBA (0x18) +# RELOCSEXP-NEXT: } + +# RELOCSEXP: Virtual Address: 0x90 +# RELOCSEXP-NEXT: Symbol: .__tls_get_addr (118) +# RELOCSEXP-NEXT: IsSigned: Yes +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 26 +# RELOCSEXP-NEXT: Type: R_RBA (0x18) +# RELOCSEXP-NEXT: } +# RELOCSEXP-NEXT: } +# RELOCSEXP-NEXT: Section (2) .data { +# RELOCSEXP-NEXT: Relocation { +# RELOCSEXP-NEXT: Virtual Address: 0x100 +# RELOCSEXP-NEXT: Symbol: A (78) +# RELOCSEXP-NEXT: IsSigned: No +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 32 +# RELOCSEXP-NEXT: Type: R_POS (0x0) +# RELOCSEXP-NEXT: } + +# RELOCSEXP: Virtual Address: 0x110 +# RELOCSEXP-NEXT: Symbol: J (96) +# RELOCSEXP-NEXT: IsSigned: No +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 32 +# RELOCSEXP-NEXT: Type: R_POS (0x0) +# RELOCSEXP-NEXT: } + +# RELOCSEXP: Virtual Address: 0x154 +# RELOCSEXP-NEXT: Symbol: TOC (72) +# RELOCSEXP-NEXT: IsSigned: No +# RELOCSEXP-NEXT: FixupBitValue: 0 +# RELOCSEXP-NEXT: Length: 32 +# RELOCSEXP-NEXT: Type: R_POS (0x0) +# RELOCSEXP-NEXT: } +# RELOCSEXP-NEXT: } +# RELOCSEXP-NEXT:] Index: llvm/tools/llvm-readobj/XCOFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -50,6 +50,7 @@ // Least significant 3 bits are reserved. static constexpr unsigned SectionFlagsReservedMask = 0x7; + template void printRelocations(ArrayRef Sections); const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -109,7 +110,53 @@ } void XCOFFDumper::printRelocations() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + if (Obj.is64Bit()) + llvm_unreachable("64-bit relocation output not implemented!"); + else + printRelocations(Obj.sections32()); +} + +static const EnumEntry ReloationTypeNameclass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(R_POS), ECase(R_NEG), ECase(R_REL), ECase(R_TOC), + ECase(R_TRL), ECase(R_TRLA), ECase(R_GL), ECase(R_TCL), + ECase(R_RL), ECase(R_RLA), ECase(R_REF), ECase(R_BA), + ECase(R_RBA), ECase(R_RBR), ECase(R_TLS), ECase(R_TLS_IE), + ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), ECase(R_TOCU), + ECase(R_TOCL) +#undef ECase +}; + +template void XCOFFDumper::printRelocations(ArrayRef Sections) { + if (!opts::ExpandRelocs) + report_fatal_error("Unexpanded relocation output not implemented."); + + ListScope LS(W, "Relocations"); + uint16_t Index = 1; + for (const T &Sec : Sections) { + auto Relocations = Obj.relocations(Sec); + if (Relocations.empty()) + continue; + + W.startLine() << "Section (" << Index << ") " << Sec.getName() << " {\n"; + for (auto Reloc : Relocations) { + StringRef SymbolName = unwrapOrError( + Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex)); + + DictScope RelocScope(W, "Relocation"); + W.printHex("Virtual Address", Reloc.VirtualAddress); + W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex); + W.printString("IsSigned", isRelocationSigned(Reloc) ? "Yes" : "No"); + W.printNumber("FixupBitValue", isFixupIndicated(Reloc) ? 1 : 0); + W.printNumber("Length", getRelocatedLength(Reloc)); + W.printEnum("Type", (uint8_t)Reloc.Type, + makeArrayRef(ReloationTypeNameclass)); + } + ++Index; + W.unindent(); + W.startLine() << "}\n"; + } } static const EnumEntry FileStringType[] = {