diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -342,6 +342,10 @@ Display symbol table of loader section. +.. option:: --loader-section-relocations + + Display relocation entries of loader section. + EXIT STATUS ----------- 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 @@ -195,36 +195,8 @@ char Padding[4]; }; -struct LoaderSectionHeader32 { - support::ubig32_t Version; - support::ubig32_t NumberOfSymTabEnt; - support::ubig32_t NumberOfRelTabEnt; - support::ubig32_t LengthOfImpidStrTbl; - support::ubig32_t NumberOfImpid; - support::big32_t OffsetToImpid; - support::ubig32_t LengthOfStrTbl; - support::big32_t OffsetToStrTbl; - - uint64_t getOffsetToSymTbl() const { - return NumberOfSymTabEnt == 0 ? 0 : sizeof(LoaderSectionHeader32); - } -}; - -struct LoaderSectionHeader64 { - support::ubig32_t Version; - support::ubig32_t NumberOfSymTabEnt; - support::ubig32_t NumberOfRelTabEnt; - support::ubig32_t LengthOfImpidStrTbl; - support::ubig32_t NumberOfImpid; - support::ubig32_t LengthOfStrTbl; - support::big64_t OffsetToImpid; - support::big64_t OffsetToStrTbl; - support::big64_t OffsetToSymTbl; - support::big64_t OffsetToRelEnt; - - uint64_t getOffsetToSymTbl() const { return OffsetToSymTbl; } -}; - +struct LoaderSectionHeader32; +struct LoaderSectionHeader64; struct LoaderSectionSymbolEntry32 { struct NameOffsetInStrTbl { support::big32_t IsNameInStrTbl; // Zero indicates name in string table. @@ -256,6 +228,59 @@ getSymbolName(const LoaderSectionHeader64 *LoaderSecHeader) const; }; +struct LoaderSectionRelocationEntry32 { + support::ubig32_t VirtualAddr; + support::big32_t SymbolIndex; + support::ubig16_t Type; + support::big16_t SectionNum; +}; + +struct LoaderSectionRelocationEntry64 { + support::ubig64_t VirtualAddr; + support::ubig16_t Type; + support::big16_t SectionNum; + support::big32_t SymbolIndex; +}; + +struct LoaderSectionHeader32 { + support::ubig32_t Version; + support::ubig32_t NumberOfSymTabEnt; + support::ubig32_t NumberOfRelTabEnt; + support::ubig32_t LengthOfImpidStrTbl; + support::ubig32_t NumberOfImpid; + support::big32_t OffsetToImpid; + support::ubig32_t LengthOfStrTbl; + support::big32_t OffsetToStrTbl; + + uint64_t getOffsetToSymTbl() const { + return NumberOfSymTabEnt == 0 ? 0 : sizeof(LoaderSectionHeader32); + } + + uint64_t getOffsetToRelEnt() const { + // Relocation table is after Symbol table. + return NumberOfRelTabEnt == 0 + ? 0 + : sizeof(LoaderSectionHeader32) + + sizeof(LoaderSectionSymbolEntry32) * NumberOfSymTabEnt; + } +}; + +struct LoaderSectionHeader64 { + support::ubig32_t Version; + support::ubig32_t NumberOfSymTabEnt; + support::ubig32_t NumberOfRelTabEnt; + support::ubig32_t LengthOfImpidStrTbl; + support::ubig32_t NumberOfImpid; + support::ubig32_t LengthOfStrTbl; + support::big64_t OffsetToImpid; + support::big64_t OffsetToStrTbl; + support::big64_t OffsetToSymTbl; + support::big64_t OffsetToRelEnt; + + uint64_t getOffsetToSymTbl() const { return OffsetToSymTbl; } + uint64_t getOffsetToRelEnt() const { return OffsetToRelEnt; } +}; + template struct ExceptionSectionEntry { union { support::ubig32_t SymbolIdx; diff --git a/llvm/test/tools/llvm-readobj/XCOFF/loader-section-relocation.test b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-relocation.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-relocation.test @@ -0,0 +1,107 @@ +## Test the --loader-section-relocations option. + +# RUN: yaml2obj --docnum=1 %s -o %t_xcoff32.o +# RUN: yaml2obj --docnum=2 %s -o %t_xcoff64.o +# RUN: llvm-readobj --loader-section-relocations %t_xcoff32.o |\ +# RUN: FileCheck %s --check-prefixes=CHECK32 +# RUN: llvm-readobj --loader-section-relocations %t_xcoff64.o |\ +# RUN: FileCheck %s --check-prefixes=CHECK64 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .loader + Flags: [ STYP_LOADER ] + SectionData: "0000000100000001000000020000016D00000001000000A400000000000000506d79696e747661722000028000021105000000000000000020000294000000011f0000022000029c000000031f000002" +## ^------- -Version=1 +## ^------- -NumberOfSymbolEntries=1 +## ^------- -NumberOfRelocationEntries=2 +## ^------- -LengthOfImportFileIDStringTable=365 +## ^------- -NumberOfImportFileIDs=1 +## ^------- -OffsetToImportFileIDs=0xA4 +## ^------- -LengthOfStringTable=0 +## ^------- -OffsetToStringTable=0 +## ^--------------- SymbolName=myintvar +## ^------- Value=0x20000280 +## ^--- sectionNumber = 2 +## ^- SymbolType=0x11 +## ^- StorageClass=0x05 +## ^------- ImportFileID=0 +## ^-------ParameterCheckType=0 +## ^------- Virtual Address = 0x20000294 +## ^------- SymbolIndex = 1 +## ^--- Type =0x1f +## ^--- Section Num =2 +## ^------- Virtual Address = 0x20000294 +## ^------- SymbolIndex = 3 +## ^--- Type =0x1f +## ^--- Section Num =2 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1F7 +Sections: + - Name: .loader + Flags: [ STYP_LOADER ] + SectionData: "0000000200000001000000020000016D000000010000001200000000000000D000000000000000700000000000000038000000000000005000000001100003000000000200021105000000000000000000000001100003283f0000020000000100000001100003383f0000020000000300096d79696e747661720000" +## ^------- -Version=2 +## ^------- -NumberOfSymbolEntries=1 +## ^------- -NumberOfRelocationEntries=2 +## ^------- -LengthOfImportFileIDStringTable=365 +## ^------- -NumberOfImportFileIDs=1 +## ^------- --LengthOfStringTable=0x12 +## ^--------------- -OffsetToImportFileIDs=0xD0 +## ^--------------- -OffsetToStringTable=0x70 +## ^--------------- -OffsetToSymbolTable=0x38 +## ^--------------- -OffsetToRelocationEntries=0x50 +## ^--------------- Value=0x0000000110000300 +## ^------- OffsetToStringTbl=2 +## ^--- sectionNumber = 2 +## ^- SymbolType=0x11 +## ^- StorageClass=0x05 +## ^------- ImportFileID=0 +## ^-------ParameterCheckType=0 +## ^--------------- VirtualAddress= 0x110000328 +## ^--- Type= 3f00 +## ^---SectionNumber = 2 +## ^------- SymbolIndex =1 +## ^--------------- VirtualAddress= 0x110000328 +## ^--- Type= 3f00 +## ^---SectionNumber = 2 +## ^------- SymbolIndex =3 +## ^-------------------StringTable + +# CHECK32: Loader Section { +# CHECK32-NEXT: Loader Section Relocations { +# CHECK32-NEXT: Relocation { +# CHECK32-NEXT: Virtual Address: 0x20000294 +# CHECK32-NEXT: Symbol: .data (1) +# CHECK32-NEXT: Type: R_POS (0x0) +# CHECK32-NEXT: SectionNUmber: 2 +# CHECK32-NEXT: } +# CHECK32-NEXT: Relocation { +# CHECK32-NEXT: Virtual Address: 0x2000029C +# CHECK32-NEXT: Symbol: myintvar (3) +# CHECK32-NEXT: Type: R_POS (0x0) +# CHECK32-NEXT: SectionNUmber: 2 +# CHECK32-NEXT: } +# CHECK32-NEXT: } +# CHECK32-NEXT: } + +# CHECK64: Loader Section { +# CHECK64-NEXT: Loader Section Relocations { +# CHECK64-NEXT: Relocation { +# CHECK64-NEXT: Virtual Address: 0x110000328 +# CHECK64-NEXT: Type: R_POS (0x0) +# CHECK64-NEXT: SectionNUmber: 2 +# CHECK64-NEXT: Symbol: .data (1) +# CHECK64-NEXT: } +# CHECK64-NEXT: Relocation { +# CHECK64-NEXT: Virtual Address: 0x110000338 +# CHECK64-NEXT: Type: R_POS (0x0) +# CHECK64-NEXT: SectionNUmber: 2 +# CHECK64-NEXT: Symbol: myintvar (3) +# CHECK64-NEXT: } +# CHECK64-NEXT: } +# CHECK64-NEXT: } diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -158,7 +158,8 @@ // Only implement for XCOFF virtual void printAuxiliaryHeader() {} virtual void printExceptionSection() {} - virtual void printLoaderSection(bool PrintHeader, bool PrintSymbolTable) {} + virtual void printLoaderSection(bool PrintHeader, bool PrintSymbolTable, + bool PrintRelocation) {} // Only implemented for MachO. virtual void printMachODataInCode() { } diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -91,6 +91,7 @@ def exception_section : FF<"exception-section" , "Display the exception section entries">, Group; def loader_section_header : FF<"loader-section-header" , "Display the loader section header">, Group; def loader_section_symbols : FF<"loader-section-symbols" , "Display the loader section symbol table">, Group; +def loader_section_relocations : FF<"loader-section-relocations" , "Display the loader section relocation entries">, Group; def help : FF<"help", "Display this help">; def version : FF<"version", "Display the version">; 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 @@ -40,7 +40,8 @@ void printNeededLibraries() override; void printStringTable() override; void printExceptionSection() override; - void printLoaderSection(bool PrintHeader, bool PrintSymbolTable) override; + void printLoaderSection(bool PrintHeader, bool PrintSymbolTable, + bool PrintRelocation) override; ScopedPrinter &getScopedPrinter() const { return W; } @@ -71,6 +72,11 @@ void printLoaderSectionSymbols(uintptr_t LoaderSectAddr); template void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr); + void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr); + template + void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr); + const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -138,7 +144,8 @@ printSectionHeaders(Obj.sections32()); } -void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbolTable) { +void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbolTable, + bool PrintRelocation) { DictScope DS(W, "Loader Section"); Expected LoaderSectionAddrOrError = Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); @@ -158,10 +165,9 @@ if (PrintSymbolTable) printLoaderSectionSymbols(LoaderSectionAddr); - // TODO: Need to add printing of relocation entry of loader section later. - // For example: - // if (PrintRelocation) - // printLoaderSectionRelocationEntry(); + if (PrintRelocation) + printLoaderSectionRelocationEntries(LoaderSectionAddr); + W.unindent(); } @@ -260,6 +266,125 @@ LoaderSectionHeader32>(LoaderSectionAddr); } +const EnumEntry RelocationTypeNameclass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), + ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), + ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), + ECase(R_BR), 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_TLSML), ECase(R_TOCU), ECase(R_TOCL) +#undef ECase +}; + +// There are five implicit external symbols, one each for the .text, .data, +// .bss, .tdata, and .tbss sections. These symbols are referenced from the +// relocation table entries using symbol table index values 0, 1, 2, -1, and -2, +// respectively. +static const char *getImplicitLoaderSectionSymName(int SymIndx) { + switch (SymIndx) { + default: + return "Unkown Symbol Name"; + case -2: + return ".tbss"; + case -1: + return ".tdata"; + case 0: + return ".text"; + case 1: + return ".data"; + case 2: + return ".bss"; + } +} + +template +void XCOFFDumper::printLoaderSectionRelocationEntriesHelper( + uintptr_t LoaderSectionAddr) { + + auto PrintLoaderSecRelocationSymIndex = [&](const auto *LoaderSecHeader, + const auto *LoaderSecRelEnt, + const auto *LoaderSecSymbol) { + Expected SymbolNameOrErr = + LoaderSecSymbol->getSymbolName(LoaderSecHeader); + if (!SymbolNameOrErr) { + reportUniqueWarning(SymbolNameOrErr.takeError()); + return; + } + W.printNumber("Symbol", SymbolNameOrErr.get(), + LoaderSecRelEnt->SymbolIndex); + }; + + auto GetLoaderSecRelSymEntPtr = [&](const auto &LoaderSecHeader, + const auto &LoaderSecRelEnt, + const auto &LoaderSecSymbol) { + // Because there are implicit symbol index (-2,-1,0,1,2), + // LoaderSecRelEnt.SymbolIndex - 3 will get real symbol information from + // symboltable. + return LoaderSectionAddr + uintptr_t(LoaderSecHeader.getOffsetToSymTbl()) + + (LoaderSecRelEnt.SymbolIndex - 3) * sizeof(LoaderSecSymbol); + }; + + const LoaderSectionHeader *LoaderSec = + reinterpret_cast(LoaderSectionAddr); + const LoaderSectionRelocationEntry *LoaderSecRelEntPtr = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt())); + const LoaderSectionSymbolEntry *LoaderSecSymEntPtr = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl())); + + for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt; + ++i, ++LoaderSecRelEntPtr) { + DictScope DS(W, "Relocation"); + W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr); + + if (Obj.is64Bit()) { + W.printEnum("Type", (uint8_t)LoaderSecRelEntPtr->Type, + makeArrayRef(RelocationTypeNameclass)); + W.printNumber("SectionNUmber", LoaderSecRelEntPtr->SectionNum); + } + + if (LoaderSecRelEntPtr->SymbolIndex >= 3) { + const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr = + reinterpret_cast(GetLoaderSecRelSymEntPtr( + *LoaderSec, *LoaderSecRelEntPtr, *LoaderSecSymEntPtr)); + + PrintLoaderSecRelocationSymIndex(LoaderSec, LoaderSecRelEntPtr, + LoaderSecRelSymEntPtr); + + } else + W.printNumber( + "Symbol", + getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex), + LoaderSecRelEntPtr->SymbolIndex); + + if (!Obj.is64Bit()) { + W.printEnum("Type", (uint8_t)LoaderSecRelEntPtr->Type, + makeArrayRef(RelocationTypeNameclass)); + W.printNumber("SectionNUmber", LoaderSecRelEntPtr->SectionNum); + } + } +} + +void XCOFFDumper::printLoaderSectionRelocationEntries( + uintptr_t LoaderSectionAddr) { + DictScope DS(W, "Loader Section Relocations"); + + if (Obj.is64Bit()) + printLoaderSectionRelocationEntriesHelper( + LoaderSectionAddr); + else + printLoaderSectionRelocationEntriesHelper( + LoaderSectionAddr); +} + template void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const { if (ExceptionSectEnt.getReason()) @@ -308,18 +433,6 @@ printRelocations(Obj.sections32()); } -const EnumEntry RelocationTypeNameclass[] = { -#define ECase(X) \ - { #X, XCOFF::X } - ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), - ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), - ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), - ECase(R_BR), 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_TLSML), ECase(R_TOCU), ECase(R_TOCL) -#undef ECase -}; - template void XCOFFDumper::printRelocation(RelTy Reloc) { Expected ErrOrSymbolName = Obj.getSymbolNameByIndex(Reloc.SymbolIndex); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -164,6 +164,7 @@ static bool XCOFFAuxiliaryHeader; static bool XCOFFLoaderSectionHeader; static bool XCOFFLoaderSectionSymbol; +static bool XCOFFLoaderSectionRelocation; static bool XCOFFExceptionSection; OutputStyleTy Output = OutputStyleTy::LLVM; @@ -307,6 +308,8 @@ opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header); opts::XCOFFLoaderSectionHeader = Args.hasArg(OPT_loader_section_header); opts::XCOFFLoaderSectionSymbol = Args.hasArg(OPT_loader_section_symbols); + opts::XCOFFLoaderSectionRelocation = + Args.hasArg(OPT_loader_section_relocations); opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section); opts::InputFilenames = Args.getAllArgValues(OPT_INPUT); @@ -512,9 +515,11 @@ } if (Obj.isXCOFF()) { - if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol) + if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol || + opts::XCOFFLoaderSectionRelocation) Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader, - opts::XCOFFLoaderSectionSymbol); + opts::XCOFFLoaderSectionSymbol, + opts::XCOFFLoaderSectionRelocation); if (opts::XCOFFExceptionSection) Dumper->printExceptionSection();