@@ -35,6 +35,11 @@ static cl::opt<bool>
35
35
DumpORC (" dump-orc" , cl::desc(" dump raw ORC unwind information (sorted)" ),
36
36
cl::init(false ), cl::Hidden, cl::cat(BoltCategory));
37
37
38
+ static cl::opt<bool > DumpStaticCalls (" dump-static-calls" ,
39
+ cl::desc (" dump Linux kernel static calls" ),
40
+ cl::init(false ), cl::Hidden,
41
+ cl::cat(BoltCategory));
42
+
38
43
} // namespace opts
39
44
40
45
// / Linux Kernel supports stack unwinding using ORC (oops rewind capability).
@@ -116,6 +121,19 @@ class LinuxKernelRewriter final : public MetadataRewriter {
116
121
// / Number of entries in the input file ORC sections.
117
122
uint64_t NumORCEntries = 0 ;
118
123
124
+ // / Section containing static call table.
125
+ ErrorOr<BinarySection &> StaticCallSection = std::errc::bad_address;
126
+ uint64_t StaticCallTableAddress = 0 ;
127
+ static constexpr size_t STATIC_CALL_ENTRY_SIZE = 8 ;
128
+
129
+ struct StaticCallInfo {
130
+ uint32_t ID; // / Identifier of the entry in the table.
131
+ BinaryFunction *Function; // / Function containing associated call.
132
+ MCSymbol *Label; // / Label attached to the call.
133
+ };
134
+ using StaticCallListType = std::vector<StaticCallInfo>;
135
+ StaticCallListType StaticCallEntries;
136
+
119
137
// / Insert an LKMarker for a given code pointer \p PC from a non-code section
120
138
// / \p SectionName.
121
139
void insertLKMarker (uint64_t PC, uint64_t SectionOffset,
@@ -152,6 +170,10 @@ class LinuxKernelRewriter final : public MetadataRewriter {
152
170
// / Update ORC data in the binary.
153
171
Error rewriteORCTables ();
154
172
173
+ // / Static call table handling.
174
+ Error readStaticCalls ();
175
+ Error rewriteStaticCalls ();
176
+
155
177
// / Mark instructions referenced by kernel metadata.
156
178
Error markInstructions ();
157
179
@@ -167,6 +189,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
167
189
if (Error E = readORCTables ())
168
190
return E;
169
191
192
+ if (Error E = readStaticCalls ())
193
+ return E;
194
+
170
195
return Error::success ();
171
196
}
172
197
@@ -181,6 +206,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
181
206
if (Error E = rewriteORCTables ())
182
207
return E;
183
208
209
+ if (Error E = rewriteStaticCalls ())
210
+ return E;
211
+
184
212
return Error::success ();
185
213
}
186
214
@@ -793,6 +821,133 @@ Error LinuxKernelRewriter::rewriteORCTables() {
793
821
return Error::success ();
794
822
}
795
823
824
+ // / The static call site table is created by objtool and contains entries in the
825
+ // / following format:
826
+ // /
827
+ // / struct static_call_site {
828
+ // / s32 addr;
829
+ // / s32 key;
830
+ // / };
831
+ // /
832
+ Error LinuxKernelRewriter::readStaticCalls () {
833
+ const BinaryData *StaticCallTable =
834
+ BC.getBinaryDataByName (" __start_static_call_sites" );
835
+ if (!StaticCallTable)
836
+ return Error::success ();
837
+
838
+ StaticCallTableAddress = StaticCallTable->getAddress ();
839
+
840
+ const BinaryData *Stop = BC.getBinaryDataByName (" __stop_static_call_sites" );
841
+ if (!Stop)
842
+ return createStringError (errc::executable_format_error,
843
+ " missing __stop_static_call_sites symbol" );
844
+
845
+ ErrorOr<BinarySection &> ErrorOrSection =
846
+ BC.getSectionForAddress (StaticCallTableAddress);
847
+ if (!ErrorOrSection)
848
+ return createStringError (errc::executable_format_error,
849
+ " no section matching __start_static_call_sites" );
850
+
851
+ StaticCallSection = *ErrorOrSection;
852
+ if (!StaticCallSection->containsAddress (Stop->getAddress () - 1 ))
853
+ return createStringError (errc::executable_format_error,
854
+ " __stop_static_call_sites not in the same section "
855
+ " as __start_static_call_sites" );
856
+
857
+ if ((Stop->getAddress () - StaticCallTableAddress) % STATIC_CALL_ENTRY_SIZE)
858
+ return createStringError (errc::executable_format_error,
859
+ " static call table size error" );
860
+
861
+ const uint64_t SectionAddress = StaticCallSection->getAddress ();
862
+ DataExtractor DE (StaticCallSection->getContents (),
863
+ BC.AsmInfo ->isLittleEndian (),
864
+ BC.AsmInfo ->getCodePointerSize ());
865
+ DataExtractor::Cursor Cursor (StaticCallTableAddress - SectionAddress);
866
+ uint32_t EntryID = 0 ;
867
+ while (Cursor && Cursor.tell () < Stop->getAddress () - SectionAddress) {
868
+ const uint64_t CallAddress =
869
+ SectionAddress + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
870
+ const uint64_t KeyAddress =
871
+ SectionAddress + Cursor.tell () + (int32_t )DE.getU32 (Cursor);
872
+
873
+ // Consume the status of the cursor.
874
+ if (!Cursor)
875
+ return createStringError (errc::executable_format_error,
876
+ " out of bounds while reading static calls" );
877
+
878
+ ++EntryID;
879
+
880
+ if (opts::DumpStaticCalls) {
881
+ outs () << " Static Call Site: " << EntryID << ' \n ' ;
882
+ outs () << " \t CallAddress: 0x" << Twine::utohexstr (CallAddress) << ' \n '
883
+ << " \t KeyAddress: 0x" << Twine::utohexstr (KeyAddress) << ' \n ' ;
884
+ }
885
+
886
+ BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (CallAddress);
887
+ if (!BF)
888
+ continue ;
889
+
890
+ if (!BC.shouldEmit (*BF))
891
+ continue ;
892
+
893
+ if (!BF->hasInstructions ())
894
+ continue ;
895
+
896
+ MCInst *Inst = BF->getInstructionAtOffset (CallAddress - BF->getAddress ());
897
+ if (!Inst)
898
+ return createStringError (errc::executable_format_error,
899
+ " no instruction at call site address 0x%" PRIx64,
900
+ CallAddress);
901
+
902
+ // Check for duplicate entries.
903
+ if (BC.MIB ->hasAnnotation (*Inst, " StaticCall" ))
904
+ return createStringError (errc::executable_format_error,
905
+ " duplicate static call site at 0x%" PRIx64,
906
+ CallAddress);
907
+
908
+ BC.MIB ->addAnnotation (*Inst, " StaticCall" , EntryID);
909
+
910
+ MCSymbol *Label = BC.MIB ->getLabel (*Inst);
911
+ if (!Label) {
912
+ Label = BC.Ctx ->createTempSymbol (" __SC_" );
913
+ BC.MIB ->setLabel (*Inst, Label);
914
+ }
915
+
916
+ StaticCallEntries.push_back ({EntryID, BF, Label});
917
+ }
918
+
919
+ outs () << " BOLT-INFO: parsed " << StaticCallEntries.size ()
920
+ << " static call entries\n " ;
921
+
922
+ return Error::success ();
923
+ }
924
+
925
+ // / The static call table is sorted during boot time in
926
+ // / static_call_sort_entries(). This makes it possible to update existing
927
+ // / entries in-place ignoring their relative order.
928
+ Error LinuxKernelRewriter::rewriteStaticCalls () {
929
+ if (!StaticCallTableAddress || !StaticCallSection)
930
+ return Error::success ();
931
+
932
+ for (auto &Entry : StaticCallEntries) {
933
+ if (!Entry.Function )
934
+ continue ;
935
+
936
+ BinaryFunction &BF = *Entry.Function ;
937
+ if (!BC.shouldEmit (BF))
938
+ continue ;
939
+
940
+ // Create a relocation against the label.
941
+ const uint64_t EntryOffset = StaticCallTableAddress -
942
+ StaticCallSection->getAddress () +
943
+ (Entry.ID - 1 ) * STATIC_CALL_ENTRY_SIZE;
944
+ StaticCallSection->addRelocation (EntryOffset, Entry.Label ,
945
+ ELF::R_X86_64_PC32, /* Addend*/ 0 );
946
+ }
947
+
948
+ return Error::success ();
949
+ }
950
+
796
951
} // namespace
797
952
798
953
std::unique_ptr<MetadataRewriter>
0 commit comments