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/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,11 +13,17 @@ #include "llvm/Object/XCOFFObjectFile.h" #include #include +#include namespace llvm { namespace object { -enum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 }; +enum { + FUNCTION_SYM = 0x20, + SYM_TYPE_MASK = 0x07, + RELOC_OVERFLOW = 65535, + NO_REL_MASK = 0x0001 +}; // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer // 'M'. Returns a pointer to the underlying object on success. @@ -314,41 +320,83 @@ } 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 && + (Sec32->VirtualAddress + Sec32->SectionSize) > RelocAddress) { + return RelocAddress - Sec32->VirtualAddress; + } + Sec32++; + } + + // Have an invalid address, return max value so that caller + // of this function could either detect it or proceed with it. + return std::numeric_limits::max(); } 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."); + const XCOFFRelocation32 *Reloc = viewAs(Rel.p); + return Reloc->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 +406,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 +450,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: 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: @@ -53,3 +56,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,29 @@ +//===-- 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(); + 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"); }