@@ -77,6 +77,11 @@ cl::opt<std::string> CompDirOverride(
7777 " location, which is used with DW_AT_dwo_name to construct a path "
7878 " to *.dwo files." ),
7979 cl::Hidden, cl::init(" " ), cl::cat(BoltCategory));
80+
81+ static cl::opt<bool >
82+ FailOnInvalidPadding (" fail-on-invalid-padding" , cl::Hidden, cl::init(false ),
83+ cl::desc(" treat invalid code padding as error" ),
84+ cl::ZeroOrMore, cl::cat(BoltCategory));
8085} // namespace opts
8186
8287namespace llvm {
@@ -942,8 +947,7 @@ std::string BinaryContext::generateJumpTableName(const BinaryFunction &BF,
942947}
943948
944949bool BinaryContext::hasValidCodePadding (const BinaryFunction &BF) {
945- // FIXME: aarch64 support is missing.
946- if (!isX86 ())
950+ if (!isX86 () && !isAArch64 ())
947951 return true ;
948952
949953 if (BF.getSize () == BF.getMaxSize ())
@@ -973,14 +977,26 @@ bool BinaryContext::hasValidCodePadding(const BinaryFunction &BF) {
973977 return Offset - StartOffset;
974978 };
975979
976- // Skip a sequence of zero bytes.
980+ // Skip a sequence of zero bytes. For AArch64 we only skip 4 bytes of zeros
981+ // in case the following zeros belong to constant island or veneer.
977982 auto skipZeros = [&]() {
978983 const uint64_t StartOffset = Offset;
979- for (; Offset < BF.getMaxSize (); ++Offset)
980- if ((*FunctionData)[Offset] != 0 )
984+ uint64_t CurrentOffset = Offset;
985+ for (; CurrentOffset < BF.getMaxSize () &&
986+ (!isAArch64 () || CurrentOffset < StartOffset + 4 );
987+ ++CurrentOffset)
988+ if ((*FunctionData)[CurrentOffset] != 0 )
981989 break ;
982990
983- return Offset - StartOffset;
991+ uint64_t NumZeros = CurrentOffset - StartOffset;
992+ if (isAArch64 ())
993+ NumZeros &= ~((uint64_t )0x3 );
994+
995+ if (NumZeros == 0 )
996+ return false ;
997+ Offset += NumZeros;
998+ InstrAddress += NumZeros;
999+ return true ;
9841000 };
9851001
9861002 // Accept the whole padding area filled with breakpoints.
@@ -993,6 +1009,8 @@ bool BinaryContext::hasValidCodePadding(const BinaryFunction &BF) {
9931009 // Some functions have a jump to the next function or to the padding area
9941010 // inserted after the body.
9951011 auto isSkipJump = [&](const MCInst &Instr) {
1012+ if (!isX86 ())
1013+ return false ;
9961014 uint64_t TargetAddress = 0 ;
9971015 if (MIB->isUnconditionalBranch (Instr) &&
9981016 MIB->evaluateBranch (Instr, InstrAddress, InstrSize, TargetAddress)) {
@@ -1004,34 +1022,73 @@ bool BinaryContext::hasValidCodePadding(const BinaryFunction &BF) {
10041022 return false ;
10051023 };
10061024
1025+ // For veneers that are not already covered by binary functions, only those
1026+ // that handleAArch64Veneer() can recognize are checked here.
1027+ auto skipAArch64Veneer = [&]() {
1028+ if (!isAArch64 () || Offset >= BF.getMaxSize ())
1029+ return false ;
1030+ BinaryFunction *BFVeneer = getBinaryFunctionContainingAddress (InstrAddress);
1031+ if (BFVeneer) {
1032+ // A binary function may have been created to point to this veneer.
1033+ Offset += BFVeneer->getSize ();
1034+ assert (Offset <= BF.getMaxSize () &&
1035+ " AArch64 veneeer goes past the max size of function" );
1036+ InstrAddress += BFVeneer->getSize ();
1037+ return true ;
1038+ }
1039+ const uint64_t AArch64VeneerSize = 12 ;
1040+ if (Offset + AArch64VeneerSize <= BF.getMaxSize () &&
1041+ handleAArch64Veneer (InstrAddress, /* MatchOnly*/ true )) {
1042+ Offset += AArch64VeneerSize;
1043+ InstrAddress += AArch64VeneerSize;
1044+ this ->errs () << " BOLT-WARNING: found unmarked AArch64 veneer at 0x"
1045+ << Twine::utohexstr (BF.getAddress () + Offset) << ' \n ' ;
1046+ return true ;
1047+ }
1048+ return false ;
1049+ };
1050+
1051+ auto skipAArch64ConstantIsland = [&]() {
1052+ if (!isAArch64 () || Offset >= BF.getMaxSize ())
1053+ return false ;
1054+ uint64_t Size;
1055+ if (BF.isInConstantIsland (InstrAddress, &Size)) {
1056+ Offset += Size;
1057+ InstrAddress += Size;
1058+ return true ;
1059+ }
1060+ return false ;
1061+ };
1062+
10071063 // Skip over nops, jumps, and zero padding. Allow interleaving (this happens).
1008- while (skipInstructions (isNoop) || skipInstructions (isSkipJump) ||
1064+ // For AArch64 also check veneers and skip constant islands.
1065+ while (skipAArch64Veneer () || skipAArch64ConstantIsland () ||
1066+ skipInstructions (isNoop) || skipInstructions (isSkipJump) ||
10091067 skipZeros ())
10101068 ;
10111069
10121070 if (Offset == BF.getMaxSize ())
10131071 return true ;
10141072
1015- if (opts::Verbosity >= 1 ) {
1016- this ->errs () << " BOLT-WARNING: bad padding at address 0x"
1017- << Twine::utohexstr (BF.getAddress () + BF.getSize ())
1018- << " starting at offset " << (Offset - BF.getSize ())
1019- << " in function " << BF << ' \n '
1020- << FunctionData->slice (BF.getSize (),
1021- BF.getMaxSize () - BF.getSize ())
1022- << ' \n ' ;
1023- }
1024-
1073+ this ->errs () << " BOLT-WARNING: bad padding at address 0x"
1074+ << Twine::utohexstr (BF.getAddress () + BF.getSize ())
1075+ << " starting at offset " << (Offset - BF.getSize ())
1076+ << " in function " << BF << ' \n '
1077+ << FunctionData->slice (BF.getSize (),
1078+ BF.getMaxSize () - BF.getSize ())
1079+ << ' \n ' ;
10251080 return false ;
10261081}
10271082
10281083void BinaryContext::adjustCodePadding () {
1084+ uint64_t NumInvalid = 0 ;
10291085 for (auto &BFI : BinaryFunctions) {
10301086 BinaryFunction &BF = BFI.second ;
10311087 if (!shouldEmit (BF))
10321088 continue ;
10331089
10341090 if (!hasValidCodePadding (BF)) {
1091+ NumInvalid++;
10351092 if (HasRelocations) {
10361093 this ->errs () << " BOLT-WARNING: function " << BF
10371094 << " has invalid padding. Ignoring the function\n " ;
@@ -1041,6 +1098,11 @@ void BinaryContext::adjustCodePadding() {
10411098 }
10421099 }
10431100 }
1101+ if (NumInvalid && opts::FailOnInvalidPadding) {
1102+ this ->errs () << " BOLT-ERROR: found " << NumInvalid
1103+ << " instance(s) of invalid code padding\n " ;
1104+ exit (1 );
1105+ }
10441106}
10451107
10461108MCSymbol *BinaryContext::registerNameAtAddress (StringRef Name, uint64_t Address,
0 commit comments