Expected<std::vector<typename ELFT::Rela>> ELFFile<ELFT>::android_relas(const Elf_Shdr *Sec) const { // This function reads relocations in Android's packed relocation format, // which is based on SLEB128 and delta encoding. Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); const uint8_t *Cur = ContentsOrErr->begin(); const uint8_t *End = ContentsOrErr->end(); if (ContentsOrErr->size() < 4 || Cur[0] != 'A' || Cur[1] != 'P' || Cur[2] != 'S' || Cur[3] != '2') return createError("invalid packed relocation header"); Cur += 4; const char *ErrStr = nullptr; auto ReadSLEB = [&]() -> int64_t { if (ErrStr) return 0; unsigned Len; int64_t Result = decodeSLEB128(Cur, &Len, End, &ErrStr); Cur += Len; return Result; }; uint64_t NumRelocs = ReadSLEB(); uint64_t Offset = ReadSLEB(); uint64_t Addend = 0; if (ErrStr) return createError(ErrStr); std::vector<Elf_Rela> Relocs; Relocs.reserve(NumRelocs); while (NumRelocs) { uint64_t NumRelocsInGroup = ReadSLEB(); if (NumRelocsInGroup > NumRelocs) return createError("relocation group unexpectedly large"); NumRelocs -= NumRelocsInGroup; uint64_t GroupFlags = ReadSLEB(); bool GroupedByInfo = GroupFlags & ELF::RELOCATION_GROUPED_BY_INFO_FLAG; bool GroupedByOffsetDelta = GroupFlags & ELF::RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG; bool GroupedByAddend = GroupFlags & ELF::RELOCATION_GROUPED_BY_ADDEND_FLAG; bool GroupHasAddend = GroupFlags & ELF::RELOCATION_GROUP_HAS_ADDEND_FLAG; uint64_t GroupOffsetDelta; if (GroupedByOffsetDelta) GroupOffsetDelta = ReadSLEB(); uint64_t GroupRInfo; if (GroupedByInfo) GroupRInfo = ReadSLEB(); if (GroupedByAddend && GroupHasAddend) Addend += ReadSLEB(); if (!GroupHasAddend) Addend = 0; for (uint64_t I = 0; I != NumRelocsInGroup; ++I) { Elf_Rela R; Offset += GroupedByOffsetDelta ? GroupOffsetDelta : ReadSLEB(); R.r_offset = Offset; R.r_info = GroupedByInfo ? GroupRInfo : ReadSLEB(); if (GroupHasAddend && !GroupedByAddend) Addend += ReadSLEB(); R.r_addend = Addend; Relocs.push_back(R); if (ErrStr) return createError(ErrStr); } if (ErrStr) return createError(ErrStr); } return Relocs; }