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-invalid-sym-name.test b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-relocation-invalid-sym-name.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-relocation-invalid-sym-name.test @@ -0,0 +1,39 @@ +## Test invalid offset to symbol string table of loader section for --loader-section-relocations option. + +# RUN: yaml2obj %s -o %t_xcoff.o +# RUN: llvm-readobj --loader-section-relocations %t_xcoff.o 2>&1 | FileCheck -DFILE=%t_xcoff.o %s + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .loader + Flags: [ STYP_LOADER ] + SectionData: "0000000100000001000000020000016D00000001000000A40000000c0000005000000000000000A22000028000021105000000000000000020000294000000011f0000022000029c000000031f000002000a66756e63305f5f467600" +## ^------- -Version=1 +## ^------- -NumberOfSymbolEntries=1 +## ^------- -NumberOfRelocationEntries=2 +## ^------- -LengthOfImportFileIDStringTable=365 +## ^------- -NumberOfImportFileIDs=1 +## ^------- -OffsetToImportFileIDs=0xA4 +## ^------- -LengthOfStringTable=12 +## ^------- -OffsetToStringTable=0x050 +## ^-------SymbolZero=0 +## ^-------OffsetToStringTbl=0xA2 (Invalid) +## ^------- 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 +## ^StringTable + +# CHECK: warning: '[[FILE]]': entry with offset 0xa2 in the loader section's string table with size 0xc is invalid 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,88 @@ +## 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 | FileCheck %s +# RUN: llvm-readobj --loader-section-relocations %t_xcoff64.o | FileCheck %s + +--- !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: "0000000200000001000000020000016D000000010000001200000000000000D000000000000000700000000000000038000000000000005000000001100003000000000200021105000000000000000000000000200002943f00000200000001000000002000029C3f0000020000000300096d79696e747661720000" +## ^------- -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= 0x20000294 +## ^--- Type= 3f00 +## ^---SectionNumber = 2 +## ^------- SymbolIndex =1 +## ^--------------- VirtualAddress= 0x20000294 +## ^--- Type= 3f00 +## ^---SectionNumber = 2 +## ^------- SymbolIndex =3 +## ^-------------------StringTable + +# CHECK: Loader Section { +# CHECK-NEXT: Loader Section Relocations { +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Virtual Address: 0x20000294 +# CHECK-NEXT: Symbol: .data (1) +# CHECK-NEXT: Type: R_POS (0x0) +# CHECK-NEXT: SectionNumber: 2 +# CHECK-NEXT: } +# CHECK-NEXT: Relocation { +# CHECK-NEXT: Virtual Address: 0x2000029C +# CHECK-NEXT: Symbol: myintvar (3) +# CHECK-NEXT: Type: R_POS (0x0) +# CHECK-NEXT: SectionNumber: 2 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-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 @@ -155,10 +155,12 @@ llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes, bool GHash) {} - // Only implement for XCOFF + // Only implemented for XCOFF. + virtual void printStringTable() {} virtual void printAuxiliaryHeader() {} virtual void printExceptionSection() {} - virtual void printLoaderSection(bool PrintHeader, bool PrintSymbolTable) {} + virtual void printLoaderSection(bool PrintHeader, bool PrintSymbols, + bool PrintRelocations) {} // Only implemented for MachO. virtual void printMachODataInCode() { } @@ -168,9 +170,6 @@ virtual void printMachOIndirectSymbols() { } virtual void printMachOLinkerOptions() { } - // Currently only implemented for XCOFF. - virtual void printStringTable() { } - virtual void printStackMap() const = 0; void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0); 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 PrintSymbols, + bool PrintRelocations) override; ScopedPrinter &getScopedPrinter() const { return W; } @@ -71,7 +72,13 @@ 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; + const static int32_t FirstSymIdxOfLoaderSec = 3; }; } // anonymous namespace @@ -138,7 +145,8 @@ printSectionHeaders(Obj.sections32()); } -void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbolTable) { +void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols, + bool PrintRelocations) { DictScope DS(W, "Loader Section"); Expected LoaderSectionAddrOrError = Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); @@ -155,13 +163,12 @@ if (PrintHeader) printLoaderSectionHeader(LoaderSectionAddr); - if (PrintSymbolTable) + if (PrintSymbols) printLoaderSectionSymbols(LoaderSectionAddr); - // TODO: Need to add printing of relocation entry of loader section later. - // For example: - // if (PrintRelocation) - // printLoaderSectionRelocationEntry(); + if (PrintRelocations) + printLoaderSectionRelocationEntries(LoaderSectionAddr); + W.unindent(); } @@ -261,6 +268,102 @@ 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 +}; + +// From the XCOFF specification: 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) { + const LoaderSectionHeader *LoaderSec = + reinterpret_cast(LoaderSectionAddr); + const LoaderSectionRelocationEntry *LoaderSecRelEntPtr = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt())); + + for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt; + ++i, ++LoaderSecRelEntPtr) { + DictScope DS(W, "Relocation"); + W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr); + + if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) { + // Because there are implicit symbol index values (-2, -1, 0, 1, 2), + // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the + // real symbol from the symbol table. + const uint64_t SymOffset = + (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) * + sizeof(LoaderSectionSymbolEntry); + const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) + + SymOffset); + + Expected SymbolNameOrErr = + LoaderSecRelSymEntPtr->getSymbolName(LoaderSec); + if (!SymbolNameOrErr) { + reportUniqueWarning(SymbolNameOrErr.takeError()); + return; + } + W.printNumber("Symbol", SymbolNameOrErr.get(), + LoaderSecRelEntPtr->SymbolIndex); + } else + W.printNumber( + "Symbol", + getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex), + LoaderSecRelEntPtr->SymbolIndex); + + W.printEnum("Type", static_cast(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()) @@ -309,18 +412,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();