[AIX][XCOFF] 64-bit relocation reading support

Support XCOFFDumper relocation reading support
This patch is part of D103696 partition

Reviewed By: daltenty, Helflym

Differential Revision: https://reviews.llvm.org/D104646
This commit is contained in:
Maryam Benimmar 2021-08-17 14:22:29 -04:00 committed by David Tenty
parent 337bd67d83
commit 2cdfd0b259
4 changed files with 175 additions and 78 deletions

View File

@ -228,7 +228,7 @@ struct XCOFFSectAuxEntForStat {
uint8_t Pad[10];
}; // 32-bit XCOFF file only.
struct XCOFFRelocation32 {
template <typename AddressType> struct XCOFFRelocation {
// Masks for packing/unpacking the r_rsize field of relocations.
// The msb is used to indicate if the bits being relocated are signed or
@ -244,7 +244,7 @@ struct XCOFFRelocation32 {
static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f;
public:
support::ubig32_t VirtualAddress;
AddressType VirtualAddress;
support::ubig32_t SymbolIndex;
// Packed field, see XR_* masks for details of packing.
@ -260,6 +260,12 @@ public:
uint8_t getRelocatedLength() const;
};
extern template struct XCOFFRelocation<llvm::support::ubig32_t>;
extern template struct XCOFFRelocation<llvm::support::ubig64_t>;
struct XCOFFRelocation32 : XCOFFRelocation<llvm::support::ubig32_t> {};
struct XCOFFRelocation64 : XCOFFRelocation<llvm::support::ubig64_t> {};
class XCOFFSymbolRef;
class XCOFFObjectFile : public ObjectFile {
@ -275,6 +281,7 @@ private:
const XCOFFSectionHeader32 *sectionHeaderTable32() const;
const XCOFFSectionHeader64 *sectionHeaderTable64() const;
template <typename T> const T *sectionHeaderTable() const;
size_t getFileHeaderSize() const;
size_t getSectionHeaderSize() const;
@ -415,11 +422,12 @@ public:
void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const;
// Relocation-related interfaces.
template <typename T>
Expected<uint32_t>
getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const;
getNumberOfRelocationEntries(const XCOFFSectionHeader<T> &Sec) const;
Expected<ArrayRef<XCOFFRelocation32>>
relocations(const XCOFFSectionHeader32 &) const;
template <typename Shdr, typename Reloc>
Expected<ArrayRef<Reloc>> relocations(const Shdr &Sec) const;
// This function returns string table entry.
Expected<StringRef> getStringTableEntry(uint32_t Offset) const;
@ -572,6 +580,7 @@ class XCOFFTracebackTable {
Optional<uint8_t> ExtensionTable;
XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err);
public:
/// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes.
/// Returns an XCOFFTracebackTable upon successful parsing, otherwise an

View File

@ -69,15 +69,18 @@ bool XCOFFSectionHeader<T>::isReservedSectionType() const {
return getSectionType() & SectionFlagsReservedMask;
}
bool XCOFFRelocation32::isRelocationSigned() const {
template <typename AddressType>
bool XCOFFRelocation<AddressType>::isRelocationSigned() const {
return Info & XR_SIGN_INDICATOR_MASK;
}
bool XCOFFRelocation32::isFixupIndicated() const {
template <typename AddressType>
bool XCOFFRelocation<AddressType>::isFixupIndicated() const {
return Info & XR_FIXUP_INDICATOR_MASK;
}
uint8_t XCOFFRelocation32::getRelocatedLength() const {
template <typename AddressType>
uint8_t XCOFFRelocation<AddressType>::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;
@ -146,6 +149,10 @@ const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
return static_cast<const XCOFFFileHeader64 *>(FileHeader);
}
template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const {
return static_cast<const T *>(SectionHeaderTable);
}
const XCOFFSectionHeader32 *
XCOFFObjectFile::sectionHeaderTable32() const {
assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
@ -329,61 +336,112 @@ bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
}
relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
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<uintptr_t>(&*RelocationsOrErr.get().begin());
if (is64Bit()) {
const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
} else {
const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
}
return relocation_iterator(RelocationRef(Ret, this));
}
relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
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<uintptr_t>(&*RelocationsOrErr.get().end());
if (is64Bit()) {
const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
} else {
const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
}
return relocation_iterator(RelocationRef(Ret, this));
}
void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);
if (is64Bit())
Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1);
else
Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);
}
uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
if (is64Bit())
report_fatal_error("64-bit support not implemented yet");
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(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;
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64();
const uint64_t RelocAddress = Reloc->VirtualAddress;
const uint16_t NumberOfSections = getNumberOfSections();
for (uint16_t I = 0; I < NumberOfSections; ++I) {
// Find which section this relocation belongs to, and get the
// relocation offset relative to the start of the section.
if (Sec64->VirtualAddress <= RelocAddress &&
RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) {
return RelocAddress - Sec64->VirtualAddress;
}
++Sec64;
}
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(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 belongs 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;
}
++Sec32;
}
return InvalidRelocOffset;
}
symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
if (is64Bit())
report_fatal_error("64-bit support not implemented yet");
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
const uint32_t Index = Reloc->SymbolIndex;
uint32_t Index;
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
Index = Reloc->SymbolIndex;
if (Index >= getLogicalNumberOfSymbolTableEntries32())
return symbol_end();
if (Index >= getNumberOfSymbolTableEntries64())
return symbol_end();
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
Index = Reloc->SymbolIndex;
if (Index >= getLogicalNumberOfSymbolTableEntries32())
return symbol_end();
}
DataRefImpl SymDRI;
SymDRI.p = getSymbolEntryAddressByIndex(Index);
return symbol_iterator(SymbolRef(SymDRI, this));
@ -391,16 +449,20 @@ symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
if (is64Bit())
report_fatal_error("64-bit support not implemented yet");
return viewAs<XCOFFRelocation64>(Rel.p)->Type;
return viewAs<XCOFFRelocation32>(Rel.p)->Type;
}
void XCOFFObjectFile::getRelocationTypeName(
DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
if (is64Bit())
report_fatal_error("64-bit support not implemented yet");
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type);
StringRef Res;
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
Res = XCOFF::getRelocationTypeString(Reloc->Type);
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
Res = XCOFF::getRelocationTypeString(Reloc->Type);
}
Result.append(Res.begin(), Res.end());
}
@ -661,13 +723,16 @@ ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
// 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 {
template <typename T>
Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries(
const XCOFFSectionHeader<T> &Sec) const {
const T &Section = static_cast<const T &>(Sec);
if (is64Bit())
return Section.NumberOfRelocations;
uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
if (Sec.NumberOfRelocations < XCOFF::RelocOverflow)
return Sec.NumberOfRelocations;
uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1;
if (Section.NumberOfRelocations < XCOFF::RelocOverflow)
return Section.NumberOfRelocations;
for (const auto &Sec : sections32()) {
if (Sec.Flags == XCOFF::STYP_OVRFLO &&
Sec.NumberOfRelocations == SectionIndex)
@ -676,27 +741,27 @@ Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
return errorCodeToError(object_error::parse_failed);
}
Expected<ArrayRef<XCOFFRelocation32>>
XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
template <typename Shdr, typename Reloc>
Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const {
uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
Sec.FileOffsetToRelocationInfo);
auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec);
if (Error E = NumRelocEntriesOrErr.takeError())
return std::move(E);
uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
static_assert(
sizeof(XCOFFRelocation32) == XCOFF::RelocationSerializationSize32, "");
static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 ||
sizeof(Reloc) == XCOFF::RelocationSerializationSize32),
"Relocation structure is incorrect");
auto RelocationOrErr =
getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
NumRelocEntries * sizeof(XCOFFRelocation32));
getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr),
NumRelocEntries * sizeof(Reloc));
if (Error E = RelocationOrErr.takeError())
return std::move(E);
const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
const Reloc *StartReloc = RelocationOrErr.get();
return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries);
}
Expected<XCOFFStringTable>
@ -900,6 +965,18 @@ Expected<StringRef> XCOFFSymbolRef::getName() const {
template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
template struct XCOFFRelocation<llvm::support::ubig32_t>;
template struct XCOFFRelocation<llvm::support::ubig64_t>;
template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>>
llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64,
llvm::object::XCOFFRelocation64>(
llvm::object::XCOFFSectionHeader64 const &) const;
template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>>
llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32,
llvm::object::XCOFFRelocation32>(
llvm::object::XCOFFSectionHeader32 const &) const;
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {
if (Bytes.size() < 4)
return false;

View File

@ -6,9 +6,8 @@
# RUN: llvm-objdump -D --symbol-description %p/Inputs/xcoff-section-headers64.o | \
# RUN: FileCheck --check-prefixes=COMMON,DESC %s
# RUN: not --crash llvm-objdump -D -r --symbol-description %p/Inputs/xcoff-section-headers64.o 2>&1 | \
# RUN: FileCheck --check-prefix=ERROR %s
# ERROR: 64-bit support not implemented yet
# RUN: llvm-objdump -D -r --symbol-description %p/Inputs/xcoff-section-headers64.o | \
# RUN: FileCheck --check-prefixes=COMMON,DESC,RELOC,COMMON-RELOC %s
## xcoff-section-headers64.o Compiled with IBM XL C/C++ for AIX, V16.1.0
## compiler command: xlc -q64 -qtls -o xcoff-section-headers64.o -c test.c
@ -29,6 +28,7 @@ COMMON-EMPTY:
PLAIN: 0000000000000000 <.func>:
DESC: 0000000000000000 (idx: 6) .func:
COMMON-NEXT: 0: e8 62 00 08 ld 3, 8(2)
RELOC-NEXT: 00000002: R_TOC (idx: 16) a[TC]
COMMON-NEXT: 4: e8 63 00 02 lwa 3, 0(3)
COMMON-NEXT: 8: 4e 80 00 20 blr
COMMON-NEXT: c: 00 00 00 00 <unknown>
@ -44,31 +44,40 @@ COMMON-EMPTY:
PLAIN: 0000000000000080 <func>:
DESC: 0000000000000080 (idx: 12) func[TC]:
COMMON-NEXT: 80: 00 00 00 00 <unknown>
RELOC-NEXT: 00000080: R_POS (idx: 10) func[DS]
COMMON-NEXT: 84: 00 00 00 a8 <unknown>
COMMON-EMPTY:
PLAIN: 0000000000000088 <a>:
DESC: 0000000000000088 (idx: 16) a[TC]:
COMMON-NEXT: 88: 00 00 00 00 <unknown>
RELOC-NEXT: 00000088: R_POS (idx: 14) a[RW]
COMMON-NEXT: 8c: 00 00 00 c8 <unknown>
COMMON-EMPTY:
PLAIN: 0000000000000090 <b>:
DESC: 0000000000000090 (idx: 20) b[TC]:
COMMON-NEXT: 90: 00 00 00 00 <unknown>
RELOC-NEXT: 00000090: R_POS (idx: 18) b[RW]
COMMON-NEXT: 94: 00 00 00 c0 <unknown>
COMMON-EMPTY:
PLAIN: 0000000000000098 <c>:
DESC: 0000000000000098 (idx: 24) c[TC]:
COMMON-NEXT: 98: 00 00 00 00 <unknown>
RELOC-NEXT: 00000098: R_TLS (idx: 22) c[UL]
COMMON-NEXT: 9c: 00 00 00 08 <unknown>
COMMON-EMPTY:
PLAIN: 00000000000000a0 <d>:
DESC: 00000000000000a0 (idx: 28) d[TC]:
COMMON-NEXT: ...
COMMON-EMPTY:
COMMON-RELOC-NEXT: a0: 00 00 00 00 <unknown>
RELOC-NEXT: 000000a0: R_TLS (idx: 26) d[TL]
COMMON-RELOC-NEXT: a4: 00 00 00 00 <unknown>
PLAIN: 00000000000000a8 <func>:
DESC: 00000000000000a8 (idx: 10) func[DS]:
COMMON-NEXT: ...
COMMON-NEXT: b4: 00 00 00 80 <unknown>
COMMON-RELOC-NEXT: a8: 00 00 00 00 <unknown>
RELOC-NEXT: 000000a8: R_POS (idx: 6) .func
COMMON-RELOC-NEXT: ac: 00 00 00 00 <unknown>
COMMON-RELOC-NEXT: b0: 00 00 00 00 <unknown>
RELOC-NEXT: 000000b0: R_POS (idx: 8) TOC[TC0]
COMMON: b4: 00 00 00 80 <unknown>
COMMON-NEXT: ...
COMMON-EMPTY:
PLAIN: 00000000000000c0 <b>:

View File

@ -44,7 +44,8 @@ private:
void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef);
void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
void printSymbol(const SymbolRef &);
void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections);
template <typename Shdr, typename RelTy>
void printRelocations(ArrayRef<Shdr> Sections);
const XCOFFObjectFile &Obj;
};
} // anonymous namespace
@ -105,9 +106,9 @@ void XCOFFDumper::printSectionHeaders() {
void XCOFFDumper::printRelocations() {
if (Obj.is64Bit())
llvm_unreachable("64-bit relocation output not implemented!");
printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
else
printRelocations(Obj.sections32());
printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
}
static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
@ -122,31 +123,32 @@ static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = {
#undef ECase
};
void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) {
template <typename Shdr, typename RelTy>
void XCOFFDumper::printRelocations(ArrayRef<Shdr> 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) {
for (const Shdr &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 ErrOrRelocations = Obj.relocations(Sec);
Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
if (Error E = ErrOrRelocations.takeError()) {
reportUniqueWarning(std::move(E));
continue;
}
auto Relocations = *ErrOrRelocations;
const ArrayRef<RelTy> Relocations = *ErrOrRelocations;
if (Relocations.empty())
continue;
W.startLine() << "Section (index: " << Index << ") " << Sec.getName()
<< " {\n";
for (auto Reloc : Relocations) {
for (const RelTy Reloc : Relocations) {
Expected<StringRef> ErrOrSymbolName =
Obj.getSymbolNameByIndex(Reloc.SymbolIndex);
if (Error E = ErrOrSymbolName.takeError()) {