Index: llvm/include/llvm/BinaryFormat/XCOFF.h =================================================================== --- llvm/include/llvm/BinaryFormat/XCOFF.h +++ llvm/include/llvm/BinaryFormat/XCOFF.h @@ -258,6 +258,7 @@ }; StringRef getMappingClassString(XCOFF::StorageMappingClass SMC); +StringRef getRelocationTypeString(XCOFF::RelocationType Type); } // end namespace XCOFF } // end namespace llvm Index: llvm/include/llvm/Object/XCOFFObjectFile.h =================================================================== --- llvm/include/llvm/Object/XCOFFObjectFile.h +++ llvm/include/llvm/Object/XCOFFObjectFile.h @@ -15,6 +15,7 @@ #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/Object/ObjectFile.h" +#include namespace llvm { namespace object { @@ -247,6 +248,9 @@ void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; public: + static constexpr uint64_t InvalidRelocOffset = + std::numeric_limits::max(); + // Interface inherited from base classes. void moveSymbolNext(DataRefImpl &Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; @@ -278,6 +282,11 @@ relocation_iterator section_rel_end(DataRefImpl Sec) const override; void moveRelocationNext(DataRefImpl &Rel) const override; + + /// Returns the relocation offset with the base address of the containing + /// section as zero. + /// Returns InvalidRelocOffset on errors (such as a + /// relocation that does not refer to an address in any section). uint64_t getRelocationOffset(DataRefImpl Rel) const override; symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; uint64_t getRelocationType(DataRefImpl Rel) const override; Index: llvm/lib/BinaryFormat/XCOFF.cpp =================================================================== --- llvm/lib/BinaryFormat/XCOFF.cpp +++ llvm/lib/BinaryFormat/XCOFF.cpp @@ -32,3 +32,36 @@ report_fatal_error("Unhandled storage-mapping class."); } } + +#define RELOC_CASE(A) \ + case XCOFF::A: \ + return #A; +StringRef XCOFF::getRelocationTypeString(XCOFF::RelocationType Type) { + switch (Type) { + RELOC_CASE(R_POS) + RELOC_CASE(R_RL) + RELOC_CASE(R_RLA) + RELOC_CASE(R_NEG) + RELOC_CASE(R_REL) + RELOC_CASE(R_TOC) + RELOC_CASE(R_TRL) + RELOC_CASE(R_TRLA) + RELOC_CASE(R_GL) + RELOC_CASE(R_TCL) + RELOC_CASE(R_REF) + RELOC_CASE(R_BA) + RELOC_CASE(R_BR) + RELOC_CASE(R_RBA) + RELOC_CASE(R_RBR) + RELOC_CASE(R_TLS) + RELOC_CASE(R_TLS_IE) + RELOC_CASE(R_TLS_LD) + RELOC_CASE(R_TLS_LE) + RELOC_CASE(R_TLSM) + RELOC_CASE(R_TLSML) + RELOC_CASE(R_TOCU) + RELOC_CASE(R_TOCL) + } + return "Unknown"; +} +#undef RELOC_CASE Index: llvm/lib/Object/XCOFFObjectFile.cpp =================================================================== --- llvm/lib/Object/XCOFFObjectFile.cpp +++ llvm/lib/Object/XCOFFObjectFile.cpp @@ -13,12 +13,18 @@ #include "llvm/Object/XCOFFObjectFile.h" #include #include +#include + +namespace { +enum { RELOC_OVERFLOW = 65535 }; +enum : uint8_t { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07 }; +enum : uint16_t { NO_REL_MASK = 0x0001 }; +static constexpr uint64_t InvalidReloc = std::numeric_limits::max(); +} // namespace namespace llvm { namespace object { -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. template @@ -314,41 +320,79 @@ } relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { - llvm_unreachable("Not yet implemented!"); - return relocation_iterator(RelocationRef()); + 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()); + return relocation_iterator(RelocationRef(Ret, this)); } relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { - llvm_unreachable("Not yet implemented!"); - return relocation_iterator(RelocationRef()); + 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()); + return relocation_iterator(RelocationRef(Ret, this)); } void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { - llvm_unreachable("Not yet implemented!"); - return; + Rel.p = reinterpret_cast(viewAs(Rel.p) + 1); } uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { - llvm_unreachable("Not yet implemented!"); - uint64_t Result = 0; - return Result; + 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; + } + ++Sec32; + } + return InvalidRelocOffset; } symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { - llvm_unreachable("Not yet implemented!"); - return symbol_iterator(SymbolRef()); + 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(); + + DataRefImpl SymDRI; + SymDRI.p = reinterpret_cast(getPointerToSymbolTable() + Index); + return symbol_iterator(SymbolRef(SymDRI, this)); } uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { - llvm_unreachable("Not yet implemented!"); - uint64_t Result = 0; - return Result; + if (is64Bit()) + report_fatal_error("64-bit support not implemented yet."); + return viewAs(Rel.p)->Type; } void XCOFFObjectFile::getRelocationTypeName( DataRefImpl Rel, SmallVectorImpl &Result) const { - llvm_unreachable("Not yet implemented!"); - return; + if (is64Bit()) + report_fatal_error("64-bit support not implemented yet."); + const XCOFFRelocation32 *Reloc = viewAs(Rel.p); + StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type); + Result.append(Res.begin(), Res.end()); } uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { @@ -358,14 +402,16 @@ } basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { - assert(!is64Bit() && "64-bit support not implemented yet."); + if (is64Bit()) + report_fatal_error("64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast(SymbolTblPtr); return basic_symbol_iterator(SymbolRef(SymDRI, this)); } basic_symbol_iterator XCOFFObjectFile::symbol_end() const { - assert(!is64Bit() && "64-bit support not implemented yet."); + if (is64Bit()) + report_fatal_error("64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast( SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); @@ -400,9 +446,9 @@ } bool XCOFFObjectFile::isRelocatableObject() const { - bool Result = false; - llvm_unreachable("Not yet implemented!"); - return Result; + if (is64Bit()) + report_fatal_error("64-bit support not implemented yet."); + return !(fileHeader32()->Flags & NO_REL_MASK); } Expected XCOFFObjectFile::getStartAddress() const { Index: llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll @@ -4,6 +4,7 @@ ; RUN: llvm-readobj --relocs --expand-relocs %t.o | FileCheck --check-prefix=RELOC %s ; RUN: llvm-readobj -t %t.o | FileCheck --check-prefix=SYM %s ; RUN: llvm-objdump -D %t.o | FileCheck --check-prefix=DIS %s +; RUN: llvm-objdump -r %t.o | FileCheck --check-prefix=DIS_REL %s ; RUN: not --crash llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc64-ibm-aix-xcoff -mattr=-altivec -filetype=obj < %s 2>&1 | \ ; RUN: FileCheck --check-prefix=XCOFF64 %s @@ -446,3 +447,17 @@ ; DIS-NEXT: 80: 00 00 00 40 ; DIS: 00000084 globalB: ; DIS-NEXT: 84: 00 00 00 44 + +; DIS_REL: {{.*}}aix-xcoff-reloc.ll.tmp.o: file format aixcoff-rs6000 +; DIS_REL: RELOCATION RECORDS FOR [.text]: +; DIS_REL-NEXT: OFFSET TYPE VALUE +; DIS_REL-NEXT: 00000010 R_RBR .bar +; DIS_REL-NEXT: 0000001a R_TOC globalA +; DIS_REL-NEXT: 0000001e R_TOC globalB +; DIS_REL: RELOCATION RECORDS FOR [.data]: +; DIS_REL-NEXT: OFFSET TYPE VALUE +; DIS_REL-NEXT: 00000030 R_POS arr +; DIS_REL-NEXT: 00000034 R_POS .foo +; DIS_REL-NEXT: 00000038 R_POS TOC +; DIS_REL-NEXT: 00000040 R_POS globalA +; DIS_REL-NEXT: 00000044 R_POS globalB Index: llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test =================================================================== --- llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test +++ llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test @@ -1,6 +1,9 @@ -# RUN: llvm-objdump -D %p/Inputs/xcoff-section-headers.o | \ +# RUN: llvm-objdump -D -r %p/Inputs/xcoff-section-headers.o | \ # RUN: FileCheck %s +# RUN: llvm-objdump -r %p/Inputs/xcoff-section-headers.o | \ +# RUN: FileCheck --check-prefix=RELOC %s + # xcoff-section-headers.o Compiled with IBM XL C/C++ for AIX, V16.1.0 # compiler command: xlc -qtls -o xcoff-section-headers.o -c test.c # test.c: @@ -17,6 +20,7 @@ CHECK: Disassembly of section .text: CHECK: 00000000 .text: CHECK-NEXT: 0: 80 62 00 04 lwz 3, 4(2) +CHECK-NEXT: 00000002: R_TOC a CHECK-NEXT: 4: 80 63 00 00 lwz 3, 0(3) CHECK-NEXT: 8: 4e 80 00 20 blr CHECK-NEXT: c: 00 00 00 00 @@ -36,7 +40,7 @@ CHECK: 0000008c c: CHECK-NEXT: 8c: 00 00 00 08 CHECK: 00000090 d: -CHECK-NEXT: 90: 00 00 00 00 +CHECK-NEXT: ... CHECK: 00000094 func: CHECK-NEXT: 94: 00 00 00 00 CHECK-NEXT: 98: 00 00 00 80 @@ -53,3 +57,17 @@ CHECK: Disassembly of section .tbss: CHECK: 00000008 c: CHECK-NEXT: ... + +RELOC: Inputs/xcoff-section-headers.o: file format aixcoff-rs6000 +RELOC: RELOCATION RECORDS FOR [.text]: +RELOC-NEXT: OFFSET TYPE VALUE +RELOC-NEXT: 00000002 R_TOC a +RELOC: RELOCATION RECORDS FOR [.data]: +RELOC-NEXT: OFFSET TYPE VALUE +RELOC-NEXT: 00000000 R_POS func +RELOC-NEXT: 00000004 R_POS a +RELOC-NEXT: 00000008 R_POS b +RELOC-NEXT: 0000000c R_TLS c +RELOC-NEXT: 00000010 R_TLS d +RELOC-NEXT: 00000014 R_POS .func +RELOC-NEXT: 00000018 R_POS TOC Index: llvm/tools/llvm-objdump/CMakeLists.txt =================================================================== --- llvm/tools/llvm-objdump/CMakeLists.txt +++ llvm/tools/llvm-objdump/CMakeLists.txt @@ -20,6 +20,7 @@ ELFDump.cpp MachODump.cpp WasmDump.cpp + XCOFFDump.cpp ) if(HAVE_LIBXAR) Index: llvm/tools/llvm-objdump/XCOFFDump.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -0,0 +1,34 @@ +//===-- XCOFFDump.cpp - XCOFF-specific dumper -------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the XCOFF-specific dumper for llvm-objdump. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/XCOFFObjectFile.h" + +using namespace llvm::object; + +llvm::Error llvm::getXCOFFRelocationValueString(const XCOFFObjectFile *Obj, + const RelocationRef &Rel, + SmallVectorImpl &Result) { + symbol_iterator SymI = Rel.getSymbol(); + if (SymI == Obj->symbol_end()) + return make_error( + "invalid symbol reference in relocation entry", + object_error::parse_failed); + + Expected SymNameOrErr = SymI->getName(); + if (!SymNameOrErr) + return SymNameOrErr.takeError(); + StringRef SymName = *SymNameOrErr; + Result.append(SymName.begin(), SymName.end()); + return Error::success(); +} Index: llvm/tools/llvm-objdump/llvm-objdump.h =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.h +++ llvm/tools/llvm-objdump/llvm-objdump.h @@ -25,6 +25,7 @@ class MachOObjectFile; class MachOUniversalBinary; class RelocationRef; +class XCOFFObjectFile; } extern cl::opt Demangle; @@ -105,6 +106,9 @@ Error getMachORelocationValueString(const object::MachOObjectFile *Obj, const object::RelocationRef &RelRef, llvm::SmallVectorImpl &Result); +Error getXCOFFRelocationValueString(const object::XCOFFObjectFile *Obj, + const object::RelocationRef &RelRef, + llvm::SmallVectorImpl &Result); uint64_t getELFSectionLMA(const object::ELFSectionRef& Sec); Index: llvm/tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.cpp +++ llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -45,6 +45,7 @@ #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -500,6 +501,8 @@ return getWasmRelocationValueString(Wasm, Rel, Result); if (auto *MachO = dyn_cast(Obj)) return getMachORelocationValueString(MachO, Rel, Result); + if (auto *XCOFF = dyn_cast(Obj)) + return getXCOFFRelocationValueString(XCOFF, Rel, Result); llvm_unreachable("unknown object file format"); }