@@ -62,6 +62,11 @@ static cl::opt<bool>
6262 cl::desc (" dump Linux kernel PCI fixup table" ),
6363 cl::init(false ), cl::Hidden, cl::cat(BoltCategory));
6464
65+ static cl::opt<bool > DumpSMPLocks (" dump-smp-locks" ,
66+ cl::desc (" dump Linux kernel SMP locks" ),
67+ cl::init(false ), cl::Hidden,
68+ cl::cat(BoltCategory));
69+
6570static cl::opt<bool > DumpStaticCalls (" dump-static-calls" ,
6671 cl::desc (" dump Linux kernel static calls" ),
6772 cl::init(false ), cl::Hidden,
@@ -119,19 +124,18 @@ inline raw_ostream &operator<<(raw_ostream &OS, const ORCState &E) {
119124namespace {
120125
121126class LinuxKernelRewriter final : public MetadataRewriter {
122- // / Linux Kernel special sections point to a specific instruction in many
123- // / cases. Unlike SDTMarkerInfo, these markers can come from different
124- // / sections.
125- struct LKInstructionMarkerInfo {
126- uint64_t SectionOffset;
127- int32_t PCRelativeOffset;
128- bool IsPCRelative;
129- StringRef SectionName;
127+ // / Information required for updating metadata referencing an instruction.
128+ struct InstructionFixup {
129+ BinarySection &Section; // Section referencing the instruction.
130+ uint64_t Offset; // Offset in the section above.
131+ BinaryFunction &BF; // Function containing the instruction.
132+ MCSymbol &Label; // Label marking the instruction.
133+ bool IsPCRelative; // If the reference type is relative.
130134 };
135+ std::vector<InstructionFixup> Fixups;
131136
132- // / Map linux kernel program locations/instructions to their pointers in
133- // / special linux kernel sections
134- std::unordered_map<uint64_t , std::vector<LKInstructionMarkerInfo>> LKMarkers;
137+ // / Size of an entry in .smp_locks section.
138+ static constexpr size_t SMP_LOCKS_ENTRY_SIZE = 4 ;
135139
136140 // / Linux ORC sections.
137141 ErrorOr<BinarySection &> ORCUnwindSection = std::errc::bad_address;
@@ -221,23 +225,20 @@ class LinuxKernelRewriter final : public MetadataRewriter {
221225 ErrorOr<BinarySection &> PCIFixupSection = std::errc::bad_address;
222226 static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16 ;
223227
224- // / Insert an LKMarker for a given code pointer \p PC from a non-code section
225- // / \p SectionName.
226- void insertLKMarker (uint64_t PC, uint64_t SectionOffset,
227- int32_t PCRelativeOffset, bool IsPCRelative,
228- StringRef SectionName);
229-
230228 // / Process linux kernel special sections and their relocations.
231229 void processLKSections ();
232230
233231 // / Process __ksymtab and __ksymtab_gpl.
234232 void processLKKSymtab (bool IsGPL = false );
235233
236- // / Process special linux kernel section, .smp_locks.
237- void processLKSMPLocks ();
234+ // Create relocations in sections requiring fixups.
235+ //
236+ // Make sure functions that will not be emitted are marked as such before this
237+ // function is executed.
238+ void processInstructionFixups ();
238239
239- // / Update LKMarkers' locations for the output binary .
240- void updateLKMarkers ();
240+ // / Process .smp_locks section .
241+ Error processSMPLocks ();
241242
242243 // / Read ORC unwind information and annotate instructions.
243244 Error readORCTables ();
@@ -282,16 +283,14 @@ class LinuxKernelRewriter final : public MetadataRewriter {
282283 Error rewriteStaticKeysJumpTable ();
283284 Error updateStaticKeysJumpTablePostEmit ();
284285
285- // / Mark instructions referenced by kernel metadata.
286- Error markInstructions ();
287-
288286public:
289287 LinuxKernelRewriter (BinaryContext &BC)
290288 : MetadataRewriter(" linux-kernel-rewriter" , BC) {}
291289
292290 Error preCFGInitializer () override {
293291 processLKSections ();
294- if (Error E = markInstructions ())
292+
293+ if (Error E = processSMPLocks ())
295294 return E;
296295
297296 if (Error E = readORCTables ())
@@ -352,12 +351,12 @@ class LinuxKernelRewriter final : public MetadataRewriter {
352351 if (Error E = rewriteBugTable ())
353352 return E;
354353
354+ processInstructionFixups ();
355+
355356 return Error::success ();
356357 }
357358
358359 Error postEmitFinalizer () override {
359- updateLKMarkers ();
360-
361360 if (Error E = updateStaticKeysJumpTablePostEmit ())
362361 return E;
363362
@@ -368,39 +367,9 @@ class LinuxKernelRewriter final : public MetadataRewriter {
368367 }
369368};
370369
371- Error LinuxKernelRewriter::markInstructions () {
372- for (const uint64_t PC : llvm::make_first_range (LKMarkers)) {
373- BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (PC);
374-
375- if (!BF || !BC.shouldEmit (*BF))
376- continue ;
377-
378- const uint64_t Offset = PC - BF->getAddress ();
379- MCInst *Inst = BF->getInstructionAtOffset (Offset);
380- if (!Inst)
381- return createStringError (errc::executable_format_error,
382- " no instruction matches kernel marker offset" );
383-
384- BC.MIB ->setOffset (*Inst, static_cast <uint32_t >(Offset));
385-
386- BF->setHasSDTMarker (true );
387- }
388-
389- return Error::success ();
390- }
391-
392- void LinuxKernelRewriter::insertLKMarker (uint64_t PC, uint64_t SectionOffset,
393- int32_t PCRelativeOffset,
394- bool IsPCRelative,
395- StringRef SectionName) {
396- LKMarkers[PC].emplace_back (LKInstructionMarkerInfo{
397- SectionOffset, PCRelativeOffset, IsPCRelative, SectionName});
398- }
399-
400370void LinuxKernelRewriter::processLKSections () {
401371 processLKKSymtab ();
402372 processLKKSymtab (true );
403- processLKSMPLocks ();
404373}
405374
406375// / Process __ksymtab[_gpl] sections of Linux Kernel.
@@ -439,79 +408,73 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) {
439408
440409// / .smp_locks section contains PC-relative references to instructions with LOCK
441410// / prefix. The prefix can be converted to NOP at boot time on non-SMP systems.
442- void LinuxKernelRewriter::processLKSMPLocks () {
443- ErrorOr<BinarySection &> SectionOrError =
411+ Error LinuxKernelRewriter::processSMPLocks () {
412+ ErrorOr<BinarySection &> SMPLocksSection =
444413 BC.getUniqueSectionByName (" .smp_locks" );
445- if (!SectionOrError )
446- return ;
414+ if (!SMPLocksSection )
415+ return Error::success () ;
447416
448- uint64_t SectionSize = SectionOrError->getSize ();
449- const uint64_t SectionAddress = SectionOrError->getAddress ();
450- assert ((SectionSize % 4 ) == 0 &&
451- " The size of the .smp_locks section should be a multiple of 4" );
417+ const uint64_t SectionSize = SMPLocksSection->getSize ();
418+ const uint64_t SectionAddress = SMPLocksSection->getAddress ();
419+ if (SectionSize % SMP_LOCKS_ENTRY_SIZE)
420+ return createStringError (errc::executable_format_error,
421+ " bad size of .smp_locks section" );
452422
453- for (uint64_t I = 0 ; I < SectionSize; I += 4 ) {
454- const uint64_t EntryAddress = SectionAddress + I;
455- ErrorOr<uint64_t > Offset = BC.getSignedValueAtAddress (EntryAddress, 4 );
456- assert (Offset && " Reading valid PC-relative offset for a .smp_locks entry" );
457- int32_t SignedOffset = *Offset;
458- uint64_t RefAddress = EntryAddress + SignedOffset;
423+ DataExtractor DE = DataExtractor (SMPLocksSection->getContents (),
424+ BC.AsmInfo ->isLittleEndian (),
425+ BC.AsmInfo ->getCodePointerSize ());
426+ DataExtractor::Cursor Cursor (0 );
427+ while (Cursor && Cursor.tell () < SectionSize) {
428+ const uint64_t Offset = Cursor.tell ();
429+ const uint64_t IP = SectionAddress + Offset + (int32_t )DE.getU32 (Cursor);
430+
431+ // Consume the status of the cursor.
432+ if (!Cursor)
433+ return createStringError (errc::executable_format_error,
434+ " error while reading .smp_locks: %s" ,
435+ toString (Cursor.takeError ()).c_str ());
459436
460- BinaryFunction *ContainingBF =
461- BC.getBinaryFunctionContainingAddress (RefAddress);
462- if (!ContainingBF)
437+ if (opts::DumpSMPLocks)
438+ BC.outs () << " SMP lock at 0x: " << Twine::utohexstr (IP) << ' \n ' ;
439+
440+ BinaryFunction *BF = BC.getBinaryFunctionContainingAddress (IP);
441+ if (!BF || !BC.shouldEmit (*BF))
463442 continue ;
464443
465- insertLKMarker (RefAddress, I, SignedOffset, true , " .smp_locks" );
466- }
467- }
444+ MCInst *Inst = BF->getInstructionAtOffset (IP - BF->getAddress ());
445+ if (!Inst)
446+ return createStringError (errc::executable_format_error,
447+ " no instruction matches lock at 0x%" PRIx64, IP);
468448
469- void LinuxKernelRewriter::updateLKMarkers () {
470- if (LKMarkers.size () == 0 )
471- return ;
449+ // Check for duplicate entries.
450+ if (BC.MIB ->hasAnnotation (*Inst, " SMPLock" ))
451+ return createStringError (errc::executable_format_error,
452+ " duplicate SMP lock at 0x%" PRIx64, IP);
472453
473- std::unordered_map<std::string, uint64_t > PatchCounts;
474- for (std::pair<const uint64_t , std::vector<LKInstructionMarkerInfo>>
475- &LKMarkerInfoKV : LKMarkers) {
476- const uint64_t OriginalAddress = LKMarkerInfoKV.first ;
477- const BinaryFunction *BF =
478- BC.getBinaryFunctionContainingAddress (OriginalAddress, false , true );
479- if (!BF)
480- continue ;
454+ BC.MIB ->addAnnotation (*Inst, " SMPLock" , true );
455+ MCSymbol *Label =
456+ BC.MIB ->getOrCreateInstLabel (*Inst, " __SMPLock_" , BC.Ctx .get ());
481457
482- uint64_t NewAddress = BF->translateInputToOutputAddress (OriginalAddress);
483- if (NewAddress == 0 )
484- continue ;
458+ Fixups.push_back ({*SMPLocksSection, Offset, *BF, *Label,
459+ /* IsPCRelative*/ true });
460+ }
461+
462+ const uint64_t NumEntries = SectionSize / SMP_LOCKS_ENTRY_SIZE;
463+ BC.outs () << " BOLT-INFO: parsed " << NumEntries << " SMP lock entries\n " ;
485464
486- // Apply base address.
487- if (OriginalAddress >= 0xffffffff00000000 && NewAddress < 0xffffffff )
488- NewAddress = NewAddress + 0xffffffff00000000 ;
465+ return Error::success ();
466+ }
489467
490- if (OriginalAddress == NewAddress)
468+ void LinuxKernelRewriter::processInstructionFixups () {
469+ for (InstructionFixup &Fixup : Fixups) {
470+ if (!BC.shouldEmit (Fixup.BF ))
491471 continue ;
492472
493- for (LKInstructionMarkerInfo &LKMarkerInfo : LKMarkerInfoKV.second ) {
494- StringRef SectionName = LKMarkerInfo.SectionName ;
495- SimpleBinaryPatcher *LKPatcher;
496- ErrorOr<BinarySection &> BSec = BC.getUniqueSectionByName (SectionName);
497- assert (BSec && " missing section info for kernel section" );
498- if (!BSec->getPatcher ())
499- BSec->registerPatcher (std::make_unique<SimpleBinaryPatcher>());
500- LKPatcher = static_cast <SimpleBinaryPatcher *>(BSec->getPatcher ());
501- PatchCounts[std::string (SectionName)]++;
502- if (LKMarkerInfo.IsPCRelative )
503- LKPatcher->addLE32Patch (LKMarkerInfo.SectionOffset ,
504- NewAddress - OriginalAddress +
505- LKMarkerInfo.PCRelativeOffset );
506- else
507- LKPatcher->addLE64Patch (LKMarkerInfo.SectionOffset , NewAddress);
508- }
473+ Fixup.Section .addRelocation (Fixup.Offset , &Fixup.Label ,
474+ Fixup.IsPCRelative ? ELF::R_X86_64_PC32
475+ : ELF::R_X86_64_64,
476+ /* Addend*/ 0 );
509477 }
510- BC.outs () << " BOLT-INFO: patching linux kernel sections. Total patches per "
511- " section are as follows:\n " ;
512- for (const std::pair<const std::string, uint64_t > &KV : PatchCounts)
513- BC.outs () << " Section: " << KV.first << " , patch-counts: " << KV.second
514- << ' \n ' ;
515478}
516479
517480Error LinuxKernelRewriter::readORCTables () {
0 commit comments