[XCOFF]implement parsing relocation information for 32-bit xcoff object file

Summary:
    Parsing the relocation entry information for 32-bit xcoff object file
including deal with the relocation overflow.

Reviewers: hubert.reinterpretcast, jasonliu, sfertile, xingxue.

Subscribers: hiraditya, rupprecht, seiya

Differential Revision: https://reviews.llvm.org/D67008

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374946 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Digger Lin
2019-10-15 20:42:11 +00:00
parent 54a7baee20
commit 5ab2259bcf
6 changed files with 380 additions and 5 deletions
+62
View File
@@ -148,6 +148,68 @@ enum SymbolType {
XTY_CM = 3 ///< Common csect definition. For uninitialized storage.
};
// Relocation types, defined in `/usr/include/reloc.h`.
enum RelocationType : uint8_t {
R_POS = 0x00, ///< Positive relocation. Provides the address of the referenced
///< symbol.
R_RL = 0x0c, ///< Positive indirect load relocation. Modifiable instruction.
R_RLA = 0x0d, ///< Positive load address relocation. Modifiable instruction.
R_NEG = 0x01, ///< Negative relocation. Provides the negative of the address
///< of the referenced symbol.
R_REL = 0x02, ///< Relative to self relocation. Provides a displacement value
///< between the address of the referenced symbol and the
///< address being relocated.
R_TOC = 0x03, ///< Relative to the TOC relocation. Provides a displacement
///< that is the difference between the address of the
///< referenced symbol and the TOC anchor csect.
R_TRL = 0x12, ///< TOC relative indirect load relocation. Similar to R_TOC,
///< but not modifiable instruction.
R_TRLA =
0x13, ///< Relative to the TOC or to the thread-local storage base
///< relocation. Compilers are not permitted to generate this
///< relocation type. It is the result of a reversible
///< transformation by the linker of an R_TOC relation that turned a
///< load instruction into an add-immediate instruction.
R_GL = 0x05, ///< Global linkage-external TOC address relocation. Provides the
///< address of the external TOC associated with a defined
///< external symbol.
R_TCL = 0x06, ///< Local object TOC address relocation. Provides the address
///< of the local TOC entry of a defined external symbol.
R_REF = 0x0f, ///< A non-relocating relocation. Used to prevent the binder
///< from garbage collecting a csect (such as code used for
///< dynamic initialization of non-local statics) for which
///< another csect has an implicit dependency.
R_BA = 0x08, ///< Branch absolute relocation. Provides the address of the
///< referenced symbol. References a non-modifiable instruction.
R_BR = 0x0a, ///< Branch relative to self relocation. Provides the
///< displacement that is the difference between the address of
///< the referenced symbol and the address of the referenced
///< branch instruction. References a non-modifiable instruction.
R_RBA = 0x18, ///< Branch absolute relocation. Similar to R_BA but
///< references a modifiable instruction.
R_RBR = 0x1a, ///< Branch relative to self relocation. Similar to the R_BR
///< relocation type, but references a modifiable instruction.
R_TLS = 0x20, ///< General-dynamic reference to TLS symbol.
R_TLS_IE = 0x21, ///< Initial-exec reference to TLS symbol.
R_TLS_LD = 0x22, ///< Local-dynamic reference to TLS symbol.
R_TLS_LE = 0x23, ///< Local-exec reference to TLS symbol.
R_TLSM = 0x24, ///< Module reference to TLS. Provides a handle for the module
///< containing the referenced symbol.
R_TLSML = 0x25, ///< Module reference to the local TLS storage.
R_TOCU = 0x30, ///< Relative to TOC upper. Specifies the high-order 16 bits of
///< a large code model TOC-relative relocation.
R_TOCL = 0x31 ///< Relative to TOC lower. Specifies the low-order 16 bits of a
///< large code model TOC-relative relocation.
};
struct FileHeader32 {
uint16_t Magic;
uint16_t NumberOfSections;
+40
View File
@@ -149,6 +149,38 @@ struct XCOFFSectAuxEntForStat {
uint8_t Pad[10];
};
struct XCOFFRelocation32 {
// 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 instruction.
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;
public:
support::ubig32_t VirtualAddress;
support::ubig32_t SymbolIndex;
// Packed field, see XR_* masks for details of packing.
uint8_t Info;
XCOFF::RelocationType Type;
public:
bool isRelocationSigned() const;
bool isFixupIndicated() const;
// Returns the number of bits being relocated.
uint8_t getRelocatedLength() const;
};
class XCOFFObjectFile : public ObjectFile {
private:
const void *FileHeader = nullptr;
@@ -278,6 +310,7 @@ public:
uint32_t getNumberOfSymbolTableEntries64() const;
uint32_t getSymbolIndex(uintptr_t SymEntPtr) const;
Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const;
Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const;
uint16_t getOptionalHeaderSize() const;
@@ -291,6 +324,13 @@ public:
Expected<DataRefImpl> getSectionByNum(int16_t Num) const;
void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const;
// Relocation-related interfaces.
Expected<uint32_t>
getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const;
Expected<ArrayRef<XCOFFRelocation32>>
relocations(const XCOFFSectionHeader32 &) const;
}; // XCOFFObjectFile
class XCOFFSymbolRef {
+68 -4
View File
@@ -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.
@@ -49,6 +46,20 @@ static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
: StringRef(Name, XCOFF::NameSize);
}
bool XCOFFRelocation32::isRelocationSigned() const {
return Info & XR_SIGN_INDICATOR_MASK;
}
bool XCOFFRelocation32::isFixupIndicated() const {
return Info & XR_FIXUP_INDICATOR_MASK;
}
uint8_t XCOFFRelocation32::getRelocatedLength() const {
// The relocation encodes the bit length being relocated minus 1. Add back
// the 1 to get the actual length being relocated.
return (Info & XR_BIASED_LENGTH_MASK) + 1;
}
void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
uintptr_t TableAddress) const {
if (Addr < TableAddress)
@@ -494,6 +505,19 @@ uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
XCOFF::SymbolTableEntrySize;
}
Expected<StringRef>
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<uintptr_t>(getPointerToSymbolTable() + Index);
return getSymbolName(SymDRI);
}
uint16_t XCOFFObjectFile::getFlags() const {
return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
}
@@ -529,6 +553,46 @@ ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
TablePtr + getNumberOfSections());
}
// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
// section header contains the actual count of relocation entries in the s_paddr
// field. STYP_OVRFLO headers contain the section index of their corresponding
// sections as their raw "NumberOfRelocations" field value.
Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
const XCOFFSectionHeader32 &Sec) const {
uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
if (Sec.NumberOfRelocations < RELOC_OVERFLOW)
return Sec.NumberOfRelocations;
for (const auto &Sec : sections32()) {
if (Sec.Flags == XCOFF::STYP_OVRFLO &&
Sec.NumberOfRelocations == SectionIndex)
return Sec.PhysicalAddress;
}
return errorCodeToError(object_error::parse_failed);
}
Expected<ArrayRef<XCOFFRelocation32>>
XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
Sec.FileOffsetToRelocationInfo);
auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
if (Error E = NumRelocEntriesOrErr.takeError())
return std::move(E);
uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
auto RelocationOrErr =
getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
NumRelocEntries * sizeof(XCOFFRelocation32));
if (Error E = RelocationOrErr.takeError())
return std::move(E);
const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
}
Expected<XCOFFStringTable>
XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
// If there is a string table, then the buffer must contain at least 4 bytes
@@ -0,0 +1,80 @@
# RUN: llvm-readobj --sections %p/Inputs/xcoff-reloc-overflow.o | \
# RUN: FileCheck --check-prefix=SECOVERFLOW %s
# RUN: llvm-readobj --relocs --expand-relocs %p/Inputs/xcoff-reloc-overflow.o | \
# RUN: FileCheck --check-prefix=RELOCOVERFLOW %s
# SECOVERFLOW: File: {{.*}}xcoff-reloc-overflow.o
# SECOVERFLOW-NEXT: Format: aixcoff-rs6000
# SECOVERFLOW-NEXT: Arch: powerpc
# SECOVERFLOW-NEXT: AddressSize: 32bit
# SECOVERFLOW-NEXT: Sections [
# SECOVERFLOW-NEXT: Section {
# SECOVERFLOW-NEXT: Index: 1
# SECOVERFLOW-NEXT: Name: .text
# SECOVERFLOW-NEXT: PhysicalAddress: 0x0
# SECOVERFLOW-NEXT: VirtualAddress: 0x0
# SECOVERFLOW-NEXT: Size: 0x38
# SECOVERFLOW-NEXT: RawDataOffset: 0x8C
# SECOVERFLOW-NEXT: RelocationPointer: 0x0
# SECOVERFLOW-NEXT: LineNumberPointer: 0x0
# SECOVERFLOW-NEXT: NumberOfRelocations: 0
# SECOVERFLOW-NEXT: NumberOfLineNumbers: 0
# SECOVERFLOW-NEXT: Type: STYP_TEXT (0x20)
# SECOVERFLOW-NEXT: }
# SECOVERFLOW-NEXT: Section {
# SECOVERFLOW-NEXT: Index: 2
# SECOVERFLOW-NEXT: Name: .data
# SECOVERFLOW-NEXT: PhysicalAddress: 0x38
# SECOVERFLOW-NEXT: VirtualAddress: 0x38
# SECOVERFLOW-NEXT: Size: 0x1C
# SECOVERFLOW-NEXT: RawDataOffset: 0xC4
# SECOVERFLOW-NEXT: RelocationPointer: 0xE0
# SECOVERFLOW-NEXT: LineNumberPointer: 0x0
# SECOVERFLOW-NEXT: NumberOfRelocations: 65535
# SECOVERFLOW-NEXT: NumberOfLineNumbers: 65535
# SECOVERFLOW-NEXT: Type: STYP_DATA (0x40)
# SECOVERFLOW-NEXT: }
# SECOVERFLOW-NEXT: Section {
# SECOVERFLOW-NEXT: Index: 3
# SECOVERFLOW-NEXT: Name: .ovrflo
# SECOVERFLOW-NEXT: NumberOfRelocations: 3
# SECOVERFLOW-NEXT: NumberOfLineNumbers: 3
# SECOVERFLOW-NEXT: Size: 0x0
# SECOVERFLOW-NEXT: RawDataOffset: 0x0
# SECOVERFLOW-NEXT: RelocationPointer: 0xE0
# SECOVERFLOW-NEXT: LineNumberPointer: 0x0
# SECOVERFLOW-NEXT: IndexOfSectionOverflowed: 2
# SECOVERFLOW-NEXT: IndexOfSectionOverflowed: 2
# SECOVERFLOW-NEXT: Type: STYP_OVRFLO (0x8000)
# SECOVERFLOW-NEXT: }
# SECOVERFLOW-NEXT: ]
# RELOCOVERFLOW: Relocations [
# RELOCOVERFLOW-NEXT: Section (index: 2) .data {
# RELOCOVERFLOW-NEXT: Relocation {
# RELOCOVERFLOW-NEXT: Virtual Address: 0x38
# RELOCOVERFLOW-NEXT: Symbol: .pb (4)
# RELOCOVERFLOW-NEXT: IsSigned: No
# RELOCOVERFLOW-NEXT: FixupBitValue: 0
# RELOCOVERFLOW-NEXT: Length: 32
# RELOCOVERFLOW-NEXT: Type: R_POS (0x0)
# RELOCOVERFLOW-NEXT: }
# RELOCOVERFLOW-NEXT: Relocation {
# RELOCOVERFLOW-NEXT: Virtual Address: 0x3C
# RELOCOVERFLOW-NEXT: Symbol: TOC (12)
# RELOCOVERFLOW-NEXT: IsSigned: No
# RELOCOVERFLOW-NEXT: FixupBitValue: 0
# RELOCOVERFLOW-NEXT: Length: 32
# RELOCOVERFLOW-NEXT: Type: R_POS (0x0)
# RELOCOVERFLOW-NEXT: }
# RELOCOVERFLOW-NEXT: Relocation {
# RELOCOVERFLOW-NEXT: Virtual Address: 0x50
# RELOCOVERFLOW-NEXT: Symbol: .text (2)
# RELOCOVERFLOW-NEXT: IsSigned: No
# RELOCOVERFLOW-NEXT: FixupBitValue: 0
# RELOCOVERFLOW-NEXT: Length: 32
# RELOCOVERFLOW-NEXT: Type: R_POS (0x0)
# RELOCOVERFLOW-NEXT: }
# RELOCOVERFLOW-NEXT: }
# RELOCOVERFLOW-NEXT: ]
+77
View File
@@ -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,77 @@
# 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 (index: 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: 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 (index: 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: 0x114
# RELOCSEXP-NEXT: Symbol: j (100)
# RELOCSEXP-NEXT: IsSigned: No
# RELOCSEXP-NEXT: FixupBitValue: 0
# RELOCSEXP-NEXT: Length: 32
# RELOCSEXP-NEXT: Type: R_TLS (0x20)
# RELOCSEXP-NEXT: }
# RELOCSEXP: Virtual Address: 0x124
# RELOCSEXP-NEXT: Symbol: d (111)
# RELOCSEXP-NEXT: IsSigned: No
# RELOCSEXP-NEXT: FixupBitValue: 0
# RELOCSEXP-NEXT: Length: 32
# RELOCSEXP-NEXT: Type: R_TLSM (0x24)
# RELOCSEXP-NEXT: }
# RELOCSEXP: Virtual Address: 0x128
# RELOCSEXP-NEXT: Symbol: (76)
# 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:]
+53 -1
View File
@@ -56,6 +56,7 @@ private:
// The low order 16 bits of section flags denotes the section type.
static constexpr unsigned SectionFlagsTypeMask = 0xffffu;
void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections);
const XCOFFObjectFile &Obj;
};
} // anonymous namespace
@@ -115,7 +116,58 @@ void XCOFFDumper::printSectionHeaders() {
}
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<XCOFF::RelocationType> 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
};
void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) {
if (!opts::ExpandRelocs)
report_fatal_error("Unexpanded relocation output not implemented.");
ListScope LS(W, "Relocations");
uint16_t Index = 0;
for (const auto &Sec : Sections) {
++Index;
// Only the .text, .data, .tdata, and STYP_DWARF sections have relocation.
if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA &&
Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF)
continue;
auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec));
if (Relocations.empty())
continue;
W.startLine() << "Section (index: " << 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", Reloc.isRelocationSigned() ? "Yes" : "No");
W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0);
W.printNumber("Length", Reloc.getRelocatedLength());
W.printEnum("Type", (uint8_t)Reloc.Type,
makeArrayRef(RelocationTypeNameclass));
}
W.unindent();
W.startLine() << "}\n";
}
}
static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {