brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · f61c08e Raw
148 lines · cpp
1//===- bolt/Rewrite/GNUPropertyRewriter.cpp -------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Read the .note.gnu.property section.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Rewrite/MetadataRewriter.h"14#include "bolt/Rewrite/MetadataRewriters.h"15#include "llvm/Support/Errc.h"16 17using namespace llvm;18using namespace bolt;19 20namespace {21 22class GNUPropertyRewriter final : public MetadataRewriter {23 24  Expected<uint32_t> decodeGNUPropertyNote(StringRef Desc);25 26public:27  GNUPropertyRewriter(StringRef Name, BinaryContext &BC)28      : MetadataRewriter(Name, BC) {}29 30  Error sectionInitializer() override;31};32 33Error GNUPropertyRewriter::sectionInitializer() {34 35  ErrorOr<BinarySection &> Sec =36      BC.getUniqueSectionByName(".note.gnu.property");37  if (!Sec)38    return Error::success();39 40  // Accumulate feature bits41  uint32_t FeaturesAcc = 0;42 43  StringRef Buf = Sec->getContents();44  DataExtractor DE(Buf, BC.AsmInfo->isLittleEndian(),45                   BC.AsmInfo->getCodePointerSize());46  DataExtractor::Cursor Cursor(0);47  while (Cursor && !DE.eof(Cursor)) {48    const uint32_t NameSz = DE.getU32(Cursor);49    const uint32_t DescSz = DE.getU32(Cursor);50    const uint32_t Type = DE.getU32(Cursor);51 52    StringRef Name =53        NameSz ? Buf.slice(Cursor.tell(), Cursor.tell() + NameSz) : "<empty>";54    Cursor.seek(alignTo(Cursor.tell() + NameSz, 4));55 56    const uint64_t DescOffset = Cursor.tell();57    StringRef Desc =58        DescSz ? Buf.slice(DescOffset, DescOffset + DescSz) : "<empty>";59    Cursor.seek(alignTo(DescOffset + DescSz, 4));60    if (!Cursor)61      return createStringError(62          errc::executable_format_error,63          "out of bounds while reading .note.gnu.property section: %s",64          toString(Cursor.takeError()).c_str());65 66    if (Type == ELF::NT_GNU_PROPERTY_TYPE_0 && Name.starts_with("GNU") &&67        DescSz) {68      auto Features = decodeGNUPropertyNote(Desc);69      if (!Features)70        return Features.takeError();71      FeaturesAcc |= *Features;72    }73  }74 75  if (BC.isAArch64()) {76    BC.setUsesBTI(FeaturesAcc & llvm::ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI);77    if (BC.usesBTI())78      BC.outs() << "BOLT-WARNING: binary is using BTI. Optimized binary may be "79                   "corrupted\n";80  }81 82  return Error::success();83}84 85/// \p Desc contains an array of property descriptors. Each member has the86/// following structure:87/// typedef struct {88///   Elf_Word pr_type;89///   Elf_Word pr_datasz;90///   unsigned char pr_data[PR_DATASZ];91///   unsigned char pr_padding[PR_PADDING];92/// } Elf_Prop;93///94/// As there is no guarantee that the features are encoded in which element of95/// the array, we have to read all, and OR together the result.96Expected<uint32_t> GNUPropertyRewriter::decodeGNUPropertyNote(StringRef Desc) {97  DataExtractor DE(Desc, BC.AsmInfo->isLittleEndian(),98                   BC.AsmInfo->getCodePointerSize());99  DataExtractor::Cursor Cursor(0);100  const uint32_t Align = DE.getAddressSize();101 102  std::optional<uint32_t> Features = 0;103  while (Cursor && !DE.eof(Cursor)) {104    const uint32_t PrType = DE.getU32(Cursor);105    const uint32_t PrDataSz = DE.getU32(Cursor);106 107    const uint64_t PrDataStart = Cursor.tell();108    const uint64_t PrDataEnd = PrDataStart + PrDataSz;109    Cursor.seek(PrDataEnd);110    if (!Cursor)111      return createStringError(112          errc::executable_format_error,113          "out of bounds while reading .note.gnu.property section: %s",114          toString(Cursor.takeError()).c_str());115 116    if (PrType == llvm::ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND) {117      if (PrDataSz != 4) {118        return createStringError(119            errc::executable_format_error,120            "Property descriptor size has to be 4 bytes on AArch64\n");121      }122      DataExtractor::Cursor Tmp(PrDataStart);123      // PrDataSz = 4 -> PrData is uint32_t124      const uint32_t FeaturesItem = DE.getU32(Tmp);125      if (!Tmp)126        return createStringError(127            errc::executable_format_error,128            "failed to read property from .note.gnu.property section: %s",129            toString(Tmp.takeError()).c_str());130      Features = Features ? (*Features | FeaturesItem) : FeaturesItem;131    }132 133    Cursor.seek(alignTo(PrDataEnd, Align));134    if (!Cursor)135      return createStringError(errc::executable_format_error,136                               "out of bounds while reading property array in "137                               ".note.gnu.property section: %s",138                               toString(Cursor.takeError()).c_str());139  }140  return Features.value_or(0u);141}142} // namespace143 144std::unique_ptr<MetadataRewriter>145llvm::bolt::createGNUPropertyRewriter(BinaryContext &BC) {146  return std::make_unique<GNUPropertyRewriter>("gnu-property-rewriter", BC);147}148