@@ -248,6 +248,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
248
248
// / Update ORC data in the binary.
249
249
Error rewriteORCTables ();
250
250
251
+ // / Validate written ORC tables after binary emission.
252
+ Error validateORCTables ();
253
+
251
254
// / Static call table handling.
252
255
Error readStaticCalls ();
253
256
Error rewriteStaticCalls ();
@@ -358,6 +361,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
358
361
if (Error E = updateStaticKeysJumpTablePostEmit ())
359
362
return E;
360
363
364
+ if (Error E = validateORCTables ())
365
+ return E;
366
+
361
367
return Error::success ();
362
368
}
363
369
};
@@ -777,11 +783,9 @@ Error LinuxKernelRewriter::rewriteORCTables() {
777
783
};
778
784
779
785
// Emit new ORC entries for the emitted function.
780
- auto emitORC = [&](const BinaryFunction &BF) -> Error {
781
- assert (!BF.isSplit () && " Split functions not supported by ORC writer yet." );
782
-
786
+ auto emitORC = [&](const FunctionFragment &FF) -> Error {
783
787
ORCState CurrentState = NullORC;
784
- for (BinaryBasicBlock *BB : BF. getLayout (). blocks () ) {
788
+ for (BinaryBasicBlock *BB : FF ) {
785
789
for (MCInst &Inst : *BB) {
786
790
ErrorOr<ORCState> ErrorOrState =
787
791
BC.MIB ->tryGetAnnotationAs <ORCState>(Inst, " ORC" );
@@ -802,7 +806,36 @@ Error LinuxKernelRewriter::rewriteORCTables() {
802
806
return Error::success ();
803
807
};
804
808
809
+ // Emit ORC entries for cold fragments. We assume that these fragments are
810
+ // emitted contiguously in memory using reserved space in the kernel. This
811
+ // assumption is validated in post-emit pass validateORCTables() where we
812
+ // check that ORC entries are sorted by their addresses.
813
+ auto emitColdORC = [&]() -> Error {
814
+ for (BinaryFunction &BF :
815
+ llvm::make_second_range (BC.getBinaryFunctions ())) {
816
+ if (!BC.shouldEmit (BF))
817
+ continue ;
818
+ for (FunctionFragment &FF : BF.getLayout ().getSplitFragments ())
819
+ if (Error E = emitORC (FF))
820
+ return E;
821
+ }
822
+
823
+ return Error::success ();
824
+ };
825
+
826
+ bool ShouldEmitCold = !BC.BOLTReserved .empty ();
805
827
for (ORCListEntry &Entry : ORCEntries) {
828
+ if (ShouldEmitCold && Entry.IP > BC.BOLTReserved .start ()) {
829
+ if (Error E = emitColdORC ())
830
+ return E;
831
+
832
+ // Emit terminator entry at the end of the reserved region.
833
+ if (Error E = emitORCEntry (BC.BOLTReserved .end (), NullORC))
834
+ return E;
835
+
836
+ ShouldEmitCold = false ;
837
+ }
838
+
806
839
// Emit original entries for functions that we haven't modified.
807
840
if (!Entry.BF || !BC.shouldEmit (*Entry.BF )) {
808
841
// Emit terminator only if it marks the start of a function.
@@ -816,7 +849,7 @@ Error LinuxKernelRewriter::rewriteORCTables() {
816
849
// Emit all ORC entries for a function referenced by an entry and skip over
817
850
// the rest of entries for this function by resetting its ORC attribute.
818
851
if (Entry.BF ->hasORC ()) {
819
- if (Error E = emitORC (* Entry.BF ))
852
+ if (Error E = emitORC (Entry.BF -> getLayout (). getMainFragment () ))
820
853
return E;
821
854
Entry.BF ->setHasORC (false );
822
855
}
@@ -825,10 +858,9 @@ Error LinuxKernelRewriter::rewriteORCTables() {
825
858
LLVM_DEBUG (dbgs () << " BOLT-DEBUG: emitted " << NumEmitted
826
859
<< " ORC entries\n " );
827
860
828
- // Replicate terminator entry at the end of sections to match the original
829
- // table sizes.
830
- const BinaryFunction &LastBF = BC.getBinaryFunctions ().rbegin ()->second ;
831
- const uint64_t LastIP = LastBF.getAddress () + LastBF.getMaxSize ();
861
+ // Populate ORC tables with a terminator entry with max address to match the
862
+ // original table sizes.
863
+ const uint64_t LastIP = std::numeric_limits<uint64_t >::max ();
832
864
while (UnwindWriter.bytesRemaining ()) {
833
865
if (Error E = emitORCEntry (LastIP, NullORC, nullptr , /* Force*/ true ))
834
866
return E;
@@ -837,6 +869,31 @@ Error LinuxKernelRewriter::rewriteORCTables() {
837
869
return Error::success ();
838
870
}
839
871
872
+ Error LinuxKernelRewriter::validateORCTables () {
873
+ if (!ORCUnwindIPSection)
874
+ return Error::success ();
875
+
876
+ const uint64_t IPSectionAddress = ORCUnwindIPSection->getAddress ();
877
+ DataExtractor IPDE = DataExtractor (ORCUnwindIPSection->getOutputContents (),
878
+ BC.AsmInfo ->isLittleEndian (),
879
+ BC.AsmInfo ->getCodePointerSize ());
880
+ DataExtractor::Cursor IPCursor (0 );
881
+ uint64_t PrevIP = 0 ;
882
+ for (uint32_t Index = 0 ; Index < NumORCEntries; ++Index) {
883
+ const uint64_t IP =
884
+ IPSectionAddress + IPCursor.tell () + (int32_t )IPDE.getU32 (IPCursor);
885
+ if (!IPCursor)
886
+ return createStringError (errc::executable_format_error,
887
+ " out of bounds while reading ORC IP table: %s" ,
888
+ toString (IPCursor.takeError ()).c_str ());
889
+
890
+ assert (IP >= PrevIP && " Unsorted ORC table detected" );
891
+ PrevIP = IP;
892
+ }
893
+
894
+ return Error::success ();
895
+ }
896
+
840
897
// / The static call site table is created by objtool and contains entries in the
841
898
// / following format:
842
899
// /
0 commit comments