[llvm] [Object][COFF][llvm-readobj] Add support for ARM64X dynamic relocations. (PR #97229)
Martin Storsjö via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 4 15:06:01 PDT 2024
================
@@ -800,6 +800,219 @@ Error COFFObjectFile::initLoadConfigPtr() {
}
}
+ // Interpret and validate dynamic relocations.
+ uint32_t DynamicRelocTableOffset = 0, DynamicRelocTableSection = 0;
+ if (is64()) {
+ auto Config = getLoadConfig64();
+ if (Config->Size >=
+ offsetof(coff_load_configuration64, DynamicValueRelocTableSection) +
+ sizeof(Config->DynamicValueRelocTableSection)) {
+ DynamicRelocTableSection = Config->DynamicValueRelocTableSection;
+ DynamicRelocTableOffset = Config->DynamicValueRelocTableOffset;
+ }
+ } else {
+ auto Config = getLoadConfig32();
+ if (Config->Size >=
+ offsetof(coff_load_configuration32, DynamicValueRelocTableSection) +
+ sizeof(Config->DynamicValueRelocTableSection)) {
+ DynamicRelocTableSection = Config->DynamicValueRelocTableSection;
+ DynamicRelocTableOffset = Config->DynamicValueRelocTableOffset;
+ }
+ }
+
+ Expected<const coff_section *> Section = getSection(DynamicRelocTableSection);
+ if (!Section)
+ return Section.takeError();
+ if (*Section) {
+ ArrayRef<uint8_t> Contents;
+ if (Error E = getSectionContents(*Section, Contents))
+ return E;
+
+ Contents = Contents.drop_front(DynamicRelocTableOffset);
+ if (Contents.size() < sizeof(coff_dynamic_reloc_table))
+ return createStringError(object_error::parse_failed,
+ "Too large DynamicValueRelocTableOffset (" +
+ Twine(DynamicRelocTableOffset) + ")");
+
+ DynamicRelocTable =
+ reinterpret_cast<const coff_dynamic_reloc_table *>(Contents.data());
+
+ if (DynamicRelocTable->Version != 1 && DynamicRelocTable->Version != 2)
+ return createStringError(
+ object_error::parse_failed,
+ "Unsupported dynamic relocations table version (" +
+ Twine(DynamicRelocTable->Version) + ")");
+
+ Contents = Contents.drop_front(sizeof(*DynamicRelocTable));
+ if (DynamicRelocTable->Size > Contents.size())
+ return createStringError(object_error::parse_failed,
+ "Indvalid dynamic relocations directory size (" +
+ Twine(DynamicRelocTable->Size) + ")");
+ Contents = Contents.take_front(DynamicRelocTable->Size);
+
+ while (!Contents.empty()) {
+ uint32_t DynRelocSize;
+ uint64_t Symbol;
+
+ if (DynamicRelocTable->Version == 1) {
+ if (is64()) {
+ if (Contents.size() < sizeof(coff_dynamic_relocation64))
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected end of dynamic relocations data");
+
+ auto DynReloc = reinterpret_cast<const coff_dynamic_relocation64 *>(
+ Contents.data());
+ Symbol = DynReloc->Symbol;
+ DynRelocSize = DynReloc->BaseRelocSize;
+ Contents = Contents.drop_front(sizeof(*DynReloc));
+ } else {
+ if (Contents.size() < sizeof(coff_dynamic_relocation32))
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected end of dynamic relocations data");
+
+ auto DynReloc = reinterpret_cast<const coff_dynamic_relocation32 *>(
+ Contents.data());
+ Symbol = DynReloc->Symbol;
+ DynRelocSize = DynReloc->BaseRelocSize;
+ Contents = Contents.drop_front(sizeof(*DynReloc));
+ }
+ } else {
+ if (is64()) {
+ if (Contents.size() < sizeof(coff_dynamic_relocation64_v2))
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected end of dynamic relocations data");
+
+ auto DynReloc =
+ reinterpret_cast<const coff_dynamic_relocation64_v2 *>(
+ Contents.data());
+ if (DynReloc->HeaderSize < sizeof(*DynReloc) ||
+ Contents.size() < DynReloc->HeaderSize)
+ return createStringError(
+ object_error::parse_failed,
+ "Invalid dynamic relocation header size (" +
+ Twine(DynReloc->HeaderSize) + ")");
+
+ Symbol = DynReloc->Symbol;
+ DynRelocSize = DynReloc->FixupInfoSize;
+ Contents = Contents.drop_front(DynReloc->HeaderSize);
+ } else {
+ if (Contents.size() < sizeof(coff_dynamic_relocation32_v2))
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected end of dynamic relocations data");
+
+ auto DynReloc =
+ reinterpret_cast<const coff_dynamic_relocation32_v2 *>(
+ Contents.data());
+ if (DynReloc->HeaderSize < sizeof(*DynReloc) ||
+ Contents.size() < DynReloc->HeaderSize)
+ return createStringError(
+ object_error::parse_failed,
+ "Invalid dynamic relocation header size (" +
+ Twine(DynReloc->HeaderSize) + ")");
+
+ Symbol = DynReloc->Symbol;
+ DynRelocSize = DynReloc->FixupInfoSize;
+ Contents = Contents.drop_front(DynReloc->HeaderSize);
+ }
+ }
+ if (DynRelocSize > Contents.size())
+ return createStringError(object_error::parse_failed,
+ "Too large dynamic relocation size (" +
+ Twine(DynRelocSize) + ")");
+
+ ArrayRef<uint8_t> RelocContents = Contents.take_front(DynRelocSize);
+ Contents = Contents.drop_front(DynRelocSize);
+
+ switch (Symbol) {
+ case COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X:
+ while (!RelocContents.empty()) {
+ if (RelocContents.size() < sizeof(coff_base_reloc_block_header))
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected end of ARM64X relocations data");
+
+ auto Header = reinterpret_cast<const coff_base_reloc_block_header *>(
+ RelocContents.data());
+ if (Header->BlockSize <= sizeof(*Header))
+ return createStringError(object_error::parse_failed,
+ "ARM64X relocations block size (" +
+ Twine(Header->BlockSize) +
+ ") is too small");
+ if (Header->BlockSize % sizeof(uint32_t))
+ return createStringError(
+ object_error::parse_failed,
+ "Unaligned ARM64X relocations block size (" +
+ Twine(Header->BlockSize) + ")");
+ if (Header->BlockSize > RelocContents.size())
+ return createStringError(object_error::parse_failed,
+ "ARM64X relocations block size (" +
+ Twine(Header->BlockSize) +
+ ") is too large");
+ if (Header->PageRVA & 0xfff)
+ return createStringError(object_error::parse_failed,
+ "Unaligned ARM64X relocations page RVA (" +
+ Twine(Header->PageRVA) + ")");
+
+ ArrayRef<uint16_t> Relocs(
+ reinterpret_cast<const uint16_t *>(RelocContents.data() +
+ sizeof(*Header)),
+ (Header->BlockSize - sizeof(*Header)) / sizeof(uint16_t));
+ RelocContents = RelocContents.drop_front(Header->BlockSize);
+
+ while (!Relocs.empty()) {
+ if (!Relocs[0]) {
+ if (Relocs.size() != 1)
+ return createStringError(
+ object_error::parse_failed,
+ "Unexpected ARM64X relocations terminator");
+ break;
+ }
+
+ uint16_t Arg = Relocs[0] >> 14, RelocSize = 1, Size;
+ switch ((Relocs[0] >> 12) & 3) {
+ case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:
+ Size = 1 << Arg;
+ break;
+ case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:
+ if (!Arg)
+ return createStringError(
+ object_error::parse_failed,
+ "Invalid ARM64X relocation value size (0)");
+ Size = 1 << Arg;
+ RelocSize += Size / sizeof(Relocs[0]);
+ break;
+ case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:
+ ++RelocSize;
+ Size = sizeof(uint32_t);
+ break;
+ default:
+ return createStringError(object_error::parse_failed,
+ "Invalid relocation type");
+ }
+ if (Header->PageRVA) {
+ uint64_t IntPtr;
+ uint16_t Offset = Relocs[0] & 0xfff;
+ if (Offset % Size)
+ return createStringError(object_error::parse_failed,
+ "Unaligned ARM64X relocation RVA (" +
+ Twine(Header->PageRVA + Offset) +
+ ")");
+ if (Error E = getRvaPtr(Header->PageRVA + Offset + Size, IntPtr,
----------------
mstorsjo wrote:
Thanks! Yes, this is exactly what I meant. The total amount of code perhaps isn't quite as small, and unfortunately, some of the terminator checking bits probably are less straightforward than before, but we don't duplicate the whole layout/iteration handling logic - which was what I disliked before.
https://github.com/llvm/llvm-project/pull/97229
More information about the llvm-commits
mailing list