@@ -242,7 +242,7 @@ class ReflectionContext
242
242
auto Buf =
243
243
this ->getReader ().readBytes (ImageStart, sizeof (typename T::Header));
244
244
if (!Buf)
245
- return false ;
245
+ return {} ;
246
246
auto Header = reinterpret_cast <typename T::Header *>(Buf.get ());
247
247
assert (Header->magic == T::MagicNumber && " invalid MachO file" );
248
248
@@ -262,7 +262,7 @@ class ReflectionContext
262
262
RemoteAddress (CmdStartAddress.getAddressData () + Offset),
263
263
SegmentCmdHdrSize);
264
264
if (!CmdBuf)
265
- return false ;
265
+ return {} ;
266
266
auto CmdHdr = reinterpret_cast <typename T::SegmentCmd *>(CmdBuf.get ());
267
267
if (strncmp (CmdHdr->segname , " __TEXT" , sizeof (CmdHdr->segname )) == 0 ) {
268
268
TextCommand = CmdHdr;
@@ -274,7 +274,7 @@ class ReflectionContext
274
274
275
275
// No __TEXT segment, bail out.
276
276
if (!TextCommand)
277
- return false ;
277
+ return {} ;
278
278
279
279
// Find the load command offset.
280
280
auto loadCmdOffset = ImageStart.getAddressData () + Offset + sizeof (typename T::Header);
@@ -284,7 +284,7 @@ class ReflectionContext
284
284
auto LoadCmdBuf = this ->getReader ().readBytes (
285
285
RemoteAddress (LoadCmdAddress), sizeof (typename T::SegmentCmd));
286
286
if (!LoadCmdBuf)
287
- return false ;
287
+ return {} ;
288
288
auto LoadCmd = reinterpret_cast <typename T::SegmentCmd *>(LoadCmdBuf.get ());
289
289
290
290
// The sections start immediately after the load command.
@@ -294,7 +294,7 @@ class ReflectionContext
294
294
auto Sections = this ->getReader ().readBytes (
295
295
RemoteAddress (SectAddress), NumSect * sizeof (typename T::Section));
296
296
if (!Sections)
297
- return false ;
297
+ return {} ;
298
298
299
299
auto Slide = ImageStart.getAddressData () - TextCommand->vmaddr ;
300
300
auto SectionsBuf = reinterpret_cast <const char *>(Sections.get ());
@@ -346,7 +346,7 @@ class ReflectionContext
346
346
ReflStrMdSec.first == nullptr &&
347
347
ConformMdSec.first == nullptr &&
348
348
MPEnumMdSec.first == nullptr )
349
- return false ;
349
+ return {} ;
350
350
351
351
ReflectionInfo info = {{FieldMdSec.first , FieldMdSec.second },
352
352
{AssocTySec.first , AssocTySec.second },
@@ -371,7 +371,7 @@ class ReflectionContext
371
371
RemoteAddress (CmdStartAddress.getAddressData () + Offset),
372
372
SegmentCmdHdrSize);
373
373
if (!CmdBuf)
374
- return false ;
374
+ return {} ;
375
375
auto CmdHdr = reinterpret_cast <typename T::SegmentCmd *>(CmdBuf.get ());
376
376
// Look for any segment name starting with __DATA or __AUTH.
377
377
if (strncmp (CmdHdr->segname , " __DATA" , 6 ) == 0 ||
@@ -398,7 +398,7 @@ class ReflectionContext
398
398
auto DOSHdrBuf = this ->getReader ().readBytes (
399
399
ImageStart, sizeof (llvm::object::dos_header));
400
400
if (!DOSHdrBuf)
401
- return false ;
401
+ return {} ;
402
402
auto DOSHdr =
403
403
reinterpret_cast <const llvm::object::dos_header *>(DOSHdrBuf.get ());
404
404
auto COFFFileHdrAddr = ImageStart.getAddressData () +
@@ -408,7 +408,7 @@ class ReflectionContext
408
408
auto COFFFileHdrBuf = this ->getReader ().readBytes (
409
409
RemoteAddress (COFFFileHdrAddr), sizeof (llvm::object::coff_file_header));
410
410
if (!COFFFileHdrBuf)
411
- return false ;
411
+ return {} ;
412
412
auto COFFFileHdr = reinterpret_cast <const llvm::object::coff_file_header *>(
413
413
COFFFileHdrBuf.get ());
414
414
@@ -419,7 +419,7 @@ class ReflectionContext
419
419
RemoteAddress (SectionTableAddr),
420
420
sizeof (llvm::object::coff_section) * COFFFileHdr->NumberOfSections );
421
421
if (!SectionTableBuf)
422
- return false ;
422
+ return {} ;
423
423
424
424
auto findCOFFSectionByName =
425
425
[&](llvm::StringRef Name) -> std::pair<RemoteRef<void >, uint64_t > {
@@ -481,7 +481,7 @@ class ReflectionContext
481
481
ReflStrMdSec.first == nullptr &&
482
482
ConformMdSec.first == nullptr &&
483
483
MPEnumMdSec.first == nullptr )
484
- return false ;
484
+ return {} ;
485
485
486
486
ReflectionInfo Info = {{FieldMdSec.first , FieldMdSec.second },
487
487
{AssocTySec.first , AssocTySec.second },
@@ -502,7 +502,7 @@ class ReflectionContext
502
502
auto Buf = this ->getReader ().readBytes (ImageStart,
503
503
sizeof (llvm::object::dos_header));
504
504
if (!Buf)
505
- return false ;
505
+ return {} ;
506
506
507
507
auto DOSHdr = reinterpret_cast <const llvm::object::dos_header *>(Buf.get ());
508
508
@@ -512,10 +512,10 @@ class ReflectionContext
512
512
Buf = this ->getReader ().readBytes (RemoteAddress (PEHeaderAddress),
513
513
sizeof (llvm::COFF::PEMagic));
514
514
if (!Buf)
515
- return false ;
515
+ return {} ;
516
516
517
517
if (memcmp (Buf.get (), llvm::COFF::PEMagic, sizeof (llvm::COFF::PEMagic)))
518
- return false ;
518
+ return {} ;
519
519
520
520
return readPECOFFSections (ImageStart, PotentialModuleNames);
521
521
}
@@ -550,7 +550,7 @@ class ReflectionContext
550
550
551
551
const void *Buf = readData (0 , sizeof (typename T::Header));
552
552
if (!Buf)
553
- return false ;
553
+ return {} ;
554
554
auto Hdr = reinterpret_cast <const typename T::Header *>(Buf);
555
555
assert (Hdr->getFileClass () == T::ELFClass && " invalid ELF file class" );
556
556
@@ -560,9 +560,9 @@ class ReflectionContext
560
560
uint16_t SectionEntrySize = Hdr->e_shentsize ;
561
561
562
562
if (sizeof (typename T::Section) > SectionEntrySize)
563
- return false ;
563
+ return {} ;
564
564
if (SectionHdrNumEntries == 0 )
565
- return false ;
565
+ return {} ;
566
566
567
567
// Collect all the section headers, we need them to look up the
568
568
// reflection sections (by name) and the string table.
@@ -573,7 +573,7 @@ class ReflectionContext
573
573
uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize);
574
574
auto SecBuf = readData (Offset, sizeof (typename T::Section));
575
575
if (!SecBuf)
576
- return false ;
576
+ return {} ;
577
577
const typename T::Section *SecHdr =
578
578
reinterpret_cast <const typename T::Section *>(SecBuf);
579
579
@@ -597,11 +597,34 @@ class ReflectionContext
597
597
598
598
auto StrTabBuf = readData (StrTabOffset, StrTabSize);
599
599
if (!StrTabBuf)
600
- return false ;
600
+ return {} ;
601
601
auto StrTab = reinterpret_cast <const char *>(StrTabBuf);
602
602
bool Error = false ;
603
+
604
+ // GNU ld and lld both merge sections regardless of the
605
+ // `SHF_GNU_RETAIN` flag. gold, presently, does not. The Swift
606
+ // compiler has a couple of switches that control whether or not
607
+ // the reflection sections are stripped; when these are enabled,
608
+ // it will _not_ set `SHF_GNU_RETAIN` on the reflection metadata
609
+ // sections. However, `swiftrt.o` contains declarations of the
610
+ // sections _with_ the `SHF_GNU_RETAIN` flag set, which makes
611
+ // sense since at runtime we will only expect to be able to access
612
+ // reflection metadata that we said we wanted to exist at runtime.
613
+ //
614
+ // The upshot is that when linking with gold, we can end up with
615
+ // two sets of reflection metadata sections. In a normal build
616
+ // where the compiler flags are the same for every linked object,
617
+ // we'll have *either* all retained *or* all un-retained sections
618
+ // (the retained sections will still exist because of `swiftrt.o`,
619
+ // but will be empty). The only time we'd expect to have a mix is
620
+ // where some code was compiled with a different setting of the
621
+ // metadata stripping flags. If that happens, the code below will
622
+ // simply add both sets of reflection sections, with the retained
623
+ // ones added first.
624
+ //
625
+ // See also https://sourceware.org/bugzilla/show_bug.cgi?id=31415.
603
626
auto findELFSectionByName =
604
- [&](llvm::StringRef Name) -> std::pair<RemoteRef<void >, uint64_t > {
627
+ [&](llvm::StringRef Name, bool Retained ) -> std::pair<RemoteRef<void >, uint64_t > {
605
628
if (Error)
606
629
return {nullptr , 0 };
607
630
// Now for all the sections, find their name.
@@ -616,6 +639,8 @@ class ReflectionContext
616
639
std::string SecName (Start, StringSize);
617
640
if (SecName != Name)
618
641
continue ;
642
+ if (Retained != bool (Hdr->sh_flags & llvm::ELF::SHF_GNU_RETAIN))
643
+ continue ;
619
644
RemoteAddress SecStart =
620
645
RemoteAddress (ImageStart.getAddressData () + Hdr->sh_addr );
621
646
auto SecSize = Hdr->sh_size ;
@@ -649,48 +674,86 @@ class ReflectionContext
649
674
650
675
SwiftObjectFileFormatELF ObjectFileFormat;
651
676
auto FieldMdSec = findELFSectionByName (
652
- ObjectFileFormat.getSectionName (ReflectionSectionKind::fieldmd));
677
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::fieldmd), true );
653
678
auto AssocTySec = findELFSectionByName (
654
- ObjectFileFormat.getSectionName (ReflectionSectionKind::assocty));
679
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::assocty), true );
655
680
auto BuiltinTySec = findELFSectionByName (
656
- ObjectFileFormat.getSectionName (ReflectionSectionKind::builtin));
681
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::builtin), true );
657
682
auto CaptureSec = findELFSectionByName (
658
- ObjectFileFormat.getSectionName (ReflectionSectionKind::capture));
683
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::capture), true );
659
684
auto TypeRefMdSec = findELFSectionByName (
660
- ObjectFileFormat.getSectionName (ReflectionSectionKind::typeref));
685
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::typeref), true );
661
686
auto ReflStrMdSec = findELFSectionByName (
662
- ObjectFileFormat.getSectionName (ReflectionSectionKind::reflstr));
687
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::reflstr), true );
663
688
auto ConformMdSec = findELFSectionByName (
664
- ObjectFileFormat.getSectionName (ReflectionSectionKind::conform));
689
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::conform), true );
665
690
auto MPEnumMdSec = findELFSectionByName (
666
- ObjectFileFormat.getSectionName (ReflectionSectionKind::mpenum));
691
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::mpenum), true );
667
692
668
693
if (Error)
669
- return false ;
694
+ return {};
695
+
696
+ std::optional<uint32_t > result = {};
670
697
671
698
// We succeed if at least one of the sections is present in the
672
699
// ELF executable.
673
- if (FieldMdSec.first == nullptr &&
674
- AssocTySec.first == nullptr &&
675
- BuiltinTySec.first == nullptr &&
676
- CaptureSec.first == nullptr &&
677
- TypeRefMdSec.first == nullptr &&
678
- ReflStrMdSec.first == nullptr &&
679
- ConformMdSec.first == nullptr &&
680
- MPEnumMdSec.first == nullptr )
681
- return false ;
700
+ if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first ||
701
+ CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first ||
702
+ ConformMdSec.first || MPEnumMdSec.first ) {
703
+ ReflectionInfo info = {{FieldMdSec.first , FieldMdSec.second },
704
+ {AssocTySec.first , AssocTySec.second },
705
+ {BuiltinTySec.first , BuiltinTySec.second },
706
+ {CaptureSec.first , CaptureSec.second },
707
+ {TypeRefMdSec.first , TypeRefMdSec.second },
708
+ {ReflStrMdSec.first , ReflStrMdSec.second },
709
+ {ConformMdSec.first , ConformMdSec.second },
710
+ {MPEnumMdSec.first , MPEnumMdSec.second },
711
+ PotentialModuleNames};
712
+ result = this ->addReflectionInfo (info);
713
+ }
682
714
683
- ReflectionInfo info = {{FieldMdSec.first , FieldMdSec.second },
684
- {AssocTySec.first , AssocTySec.second },
685
- {BuiltinTySec.first , BuiltinTySec.second },
686
- {CaptureSec.first , CaptureSec.second },
687
- {TypeRefMdSec.first , TypeRefMdSec.second },
688
- {ReflStrMdSec.first , ReflStrMdSec.second },
689
- {ConformMdSec.first , ConformMdSec.second },
690
- {MPEnumMdSec.first , MPEnumMdSec.second },
691
- PotentialModuleNames};
715
+ // Also check for the non-retained versions of the sections; we'll
716
+ // only return a single reflection info ID if both are found (and it'll
717
+ // be the one for the retained sections if we have them), but we'll
718
+ // still add all the reflection information.
719
+ FieldMdSec = findELFSectionByName (
720
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::fieldmd), false );
721
+ AssocTySec = findELFSectionByName (
722
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::assocty), false );
723
+ BuiltinTySec = findELFSectionByName (
724
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::builtin), false );
725
+ CaptureSec = findELFSectionByName (
726
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::capture), false );
727
+ TypeRefMdSec = findELFSectionByName (
728
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::typeref), false );
729
+ ReflStrMdSec = findELFSectionByName (
730
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::reflstr), false );
731
+ ConformMdSec = findELFSectionByName (
732
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::conform), false );
733
+ MPEnumMdSec = findELFSectionByName (
734
+ ObjectFileFormat.getSectionName (ReflectionSectionKind::mpenum), false );
735
+
736
+ if (Error)
737
+ return {};
692
738
693
- return this ->addReflectionInfo (info);
739
+ if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first ||
740
+ CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first ||
741
+ ConformMdSec.first || MPEnumMdSec.first ) {
742
+ ReflectionInfo info = {{FieldMdSec.first , FieldMdSec.second },
743
+ {AssocTySec.first , AssocTySec.second },
744
+ {BuiltinTySec.first , BuiltinTySec.second },
745
+ {CaptureSec.first , CaptureSec.second },
746
+ {TypeRefMdSec.first , TypeRefMdSec.second },
747
+ {ReflStrMdSec.first , ReflStrMdSec.second },
748
+ {ConformMdSec.first , ConformMdSec.second },
749
+ {MPEnumMdSec.first , MPEnumMdSec.second },
750
+ PotentialModuleNames};
751
+ auto rid = this ->addReflectionInfo (info);
752
+ if (!result)
753
+ result = rid;
754
+ }
755
+
756
+ return result;
694
757
}
695
758
696
759
// / Parses metadata information from an ELF image. Because the Section
@@ -746,7 +809,7 @@ class ReflectionContext
746
809
// Read the first few bytes to look for a magic header.
747
810
auto Magic = this ->getReader ().readBytes (ImageStart, sizeof (uint32_t ));
748
811
if (!Magic)
749
- return false ;
812
+ return {} ;
750
813
751
814
uint32_t MagicWord;
752
815
memcpy (&MagicWord, Magic.get (), sizeof (MagicWord));
0 commit comments