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