@@ -242,7 +242,7 @@ class ReflectionContext
242242 auto Buf =
243243 this ->getReader ().readBytes (ImageStart, sizeof (typename T::Header));
244244 if (!Buf)
245- return false ;
245+ return {} ;
246246 auto Header = reinterpret_cast <typename T::Header *>(Buf.get ());
247247 assert (Header->magic == T::MagicNumber && " invalid MachO file" );
248248
@@ -262,7 +262,7 @@ class ReflectionContext
262262 RemoteAddress (CmdStartAddress.getAddressData () + Offset),
263263 SegmentCmdHdrSize);
264264 if (!CmdBuf)
265- return false ;
265+ return {} ;
266266 auto CmdHdr = reinterpret_cast <typename T::SegmentCmd *>(CmdBuf.get ());
267267 if (strncmp (CmdHdr->segname , " __TEXT" , sizeof (CmdHdr->segname )) == 0 ) {
268268 TextCommand = CmdHdr;
@@ -274,7 +274,7 @@ class ReflectionContext
274274
275275 // No __TEXT segment, bail out.
276276 if (!TextCommand)
277- return false ;
277+ return {} ;
278278
279279 // Find the load command offset.
280280 auto loadCmdOffset = ImageStart.getAddressData () + Offset + sizeof (typename T::Header);
@@ -284,7 +284,7 @@ class ReflectionContext
284284 auto LoadCmdBuf = this ->getReader ().readBytes (
285285 RemoteAddress (LoadCmdAddress), sizeof (typename T::SegmentCmd));
286286 if (!LoadCmdBuf)
287- return false ;
287+ return {} ;
288288 auto LoadCmd = reinterpret_cast <typename T::SegmentCmd *>(LoadCmdBuf.get ());
289289
290290 // The sections start immediately after the load command.
@@ -294,7 +294,7 @@ class ReflectionContext
294294 auto Sections = this ->getReader ().readBytes (
295295 RemoteAddress (SectAddress), NumSect * sizeof (typename T::Section));
296296 if (!Sections)
297- return false ;
297+ return {} ;
298298
299299 auto Slide = ImageStart.getAddressData () - TextCommand->vmaddr ;
300300 auto SectionsBuf = reinterpret_cast <const char *>(Sections.get ());
@@ -346,7 +346,7 @@ class ReflectionContext
346346 ReflStrMdSec.first == nullptr &&
347347 ConformMdSec.first == nullptr &&
348348 MPEnumMdSec.first == nullptr )
349- return false ;
349+ return {} ;
350350
351351 ReflectionInfo info = {{FieldMdSec.first , FieldMdSec.second },
352352 {AssocTySec.first , AssocTySec.second },
@@ -371,7 +371,7 @@ class ReflectionContext
371371 RemoteAddress (CmdStartAddress.getAddressData () + Offset),
372372 SegmentCmdHdrSize);
373373 if (!CmdBuf)
374- return false ;
374+ return {} ;
375375 auto CmdHdr = reinterpret_cast <typename T::SegmentCmd *>(CmdBuf.get ());
376376 // Look for any segment name starting with __DATA or __AUTH.
377377 if (strncmp (CmdHdr->segname , " __DATA" , 6 ) == 0 ||
@@ -398,7 +398,7 @@ class ReflectionContext
398398 auto DOSHdrBuf = this ->getReader ().readBytes (
399399 ImageStart, sizeof (llvm::object::dos_header));
400400 if (!DOSHdrBuf)
401- return false ;
401+ return {} ;
402402 auto DOSHdr =
403403 reinterpret_cast <const llvm::object::dos_header *>(DOSHdrBuf.get ());
404404 auto COFFFileHdrAddr = ImageStart.getAddressData () +
@@ -408,7 +408,7 @@ class ReflectionContext
408408 auto COFFFileHdrBuf = this ->getReader ().readBytes (
409409 RemoteAddress (COFFFileHdrAddr), sizeof (llvm::object::coff_file_header));
410410 if (!COFFFileHdrBuf)
411- return false ;
411+ return {} ;
412412 auto COFFFileHdr = reinterpret_cast <const llvm::object::coff_file_header *>(
413413 COFFFileHdrBuf.get ());
414414
@@ -419,7 +419,7 @@ class ReflectionContext
419419 RemoteAddress (SectionTableAddr),
420420 sizeof (llvm::object::coff_section) * COFFFileHdr->NumberOfSections );
421421 if (!SectionTableBuf)
422- return false ;
422+ return {} ;
423423
424424 auto findCOFFSectionByName =
425425 [&](llvm::StringRef Name) -> std::pair<RemoteRef<void >, uint64_t > {
@@ -481,7 +481,7 @@ class ReflectionContext
481481 ReflStrMdSec.first == nullptr &&
482482 ConformMdSec.first == nullptr &&
483483 MPEnumMdSec.first == nullptr )
484- return false ;
484+ return {} ;
485485
486486 ReflectionInfo Info = {{FieldMdSec.first , FieldMdSec.second },
487487 {AssocTySec.first , AssocTySec.second },
@@ -502,7 +502,7 @@ class ReflectionContext
502502 auto Buf = this ->getReader ().readBytes (ImageStart,
503503 sizeof (llvm::object::dos_header));
504504 if (!Buf)
505- return false ;
505+ return {} ;
506506
507507 auto DOSHdr = reinterpret_cast <const llvm::object::dos_header *>(Buf.get ());
508508
@@ -512,10 +512,10 @@ class ReflectionContext
512512 Buf = this ->getReader ().readBytes (RemoteAddress (PEHeaderAddress),
513513 sizeof (llvm::COFF::PEMagic));
514514 if (!Buf)
515- return false ;
515+ return {} ;
516516
517517 if (memcmp (Buf.get (), llvm::COFF::PEMagic, sizeof (llvm::COFF::PEMagic)))
518- return false ;
518+ return {} ;
519519
520520 return readPECOFFSections (ImageStart, PotentialModuleNames);
521521 }
@@ -550,7 +550,7 @@ class ReflectionContext
550550
551551 const void *Buf = readData (0 , sizeof (typename T::Header));
552552 if (!Buf)
553- return false ;
553+ return {} ;
554554 auto Hdr = reinterpret_cast <const typename T::Header *>(Buf);
555555 assert (Hdr->getFileClass () == T::ELFClass && " invalid ELF file class" );
556556
@@ -560,9 +560,9 @@ class ReflectionContext
560560 uint16_t SectionEntrySize = Hdr->e_shentsize ;
561561
562562 if (sizeof (typename T::Section) > SectionEntrySize)
563- return false ;
563+ return {} ;
564564 if (SectionHdrNumEntries == 0 )
565- return false ;
565+ return {} ;
566566
567567 // Collect all the section headers, we need them to look up the
568568 // reflection sections (by name) and the string table.
@@ -573,7 +573,7 @@ class ReflectionContext
573573 uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize);
574574 auto SecBuf = readData (Offset, sizeof (typename T::Section));
575575 if (!SecBuf)
576- return false ;
576+ return {} ;
577577 const typename T::Section *SecHdr =
578578 reinterpret_cast <const typename T::Section *>(SecBuf);
579579
@@ -597,11 +597,34 @@ class ReflectionContext
597597
598598 auto StrTabBuf = readData (StrTabOffset, StrTabSize);
599599 if (!StrTabBuf)
600- return false ;
600+ return {} ;
601601 auto StrTab = reinterpret_cast <const char *>(StrTabBuf);
602602 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.
603626 auto findELFSectionByName =
604- [&](llvm::StringRef Name) -> std::pair<RemoteRef<void >, uint64_t > {
627+ [&](llvm::StringRef Name, bool Retained ) -> std::pair<RemoteRef<void >, uint64_t > {
605628 if (Error)
606629 return {nullptr , 0 };
607630 // Now for all the sections, find their name.
@@ -616,6 +639,8 @@ class ReflectionContext
616639 std::string SecName (Start, StringSize);
617640 if (SecName != Name)
618641 continue ;
642+ if (Retained != bool (Hdr->sh_flags & llvm::ELF::SHF_GNU_RETAIN))
643+ continue ;
619644 RemoteAddress SecStart =
620645 RemoteAddress (ImageStart.getAddressData () + Hdr->sh_addr );
621646 auto SecSize = Hdr->sh_size ;
@@ -649,48 +674,86 @@ class ReflectionContext
649674
650675 SwiftObjectFileFormatELF ObjectFileFormat;
651676 auto FieldMdSec = findELFSectionByName (
652- ObjectFileFormat.getSectionName (ReflectionSectionKind::fieldmd));
677+ ObjectFileFormat.getSectionName (ReflectionSectionKind::fieldmd), true );
653678 auto AssocTySec = findELFSectionByName (
654- ObjectFileFormat.getSectionName (ReflectionSectionKind::assocty));
679+ ObjectFileFormat.getSectionName (ReflectionSectionKind::assocty), true );
655680 auto BuiltinTySec = findELFSectionByName (
656- ObjectFileFormat.getSectionName (ReflectionSectionKind::builtin));
681+ ObjectFileFormat.getSectionName (ReflectionSectionKind::builtin), true );
657682 auto CaptureSec = findELFSectionByName (
658- ObjectFileFormat.getSectionName (ReflectionSectionKind::capture));
683+ ObjectFileFormat.getSectionName (ReflectionSectionKind::capture), true );
659684 auto TypeRefMdSec = findELFSectionByName (
660- ObjectFileFormat.getSectionName (ReflectionSectionKind::typeref));
685+ ObjectFileFormat.getSectionName (ReflectionSectionKind::typeref), true );
661686 auto ReflStrMdSec = findELFSectionByName (
662- ObjectFileFormat.getSectionName (ReflectionSectionKind::reflstr));
687+ ObjectFileFormat.getSectionName (ReflectionSectionKind::reflstr), true );
663688 auto ConformMdSec = findELFSectionByName (
664- ObjectFileFormat.getSectionName (ReflectionSectionKind::conform));
689+ ObjectFileFormat.getSectionName (ReflectionSectionKind::conform), true );
665690 auto MPEnumMdSec = findELFSectionByName (
666- ObjectFileFormat.getSectionName (ReflectionSectionKind::mpenum));
691+ ObjectFileFormat.getSectionName (ReflectionSectionKind::mpenum), true );
667692
668693 if (Error)
669- return false ;
694+ return {};
695+
696+ std::optional<uint32_t > result = {};
670697
671698 // We succeed if at least one of the sections is present in the
672699 // 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+ }
682714
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 {};
692738
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;
694757 }
695758
696759 // / Parses metadata information from an ELF image. Because the Section
@@ -746,7 +809,7 @@ class ReflectionContext
746809 // Read the first few bytes to look for a magic header.
747810 auto Magic = this ->getReader ().readBytes (ImageStart, sizeof (uint32_t ));
748811 if (!Magic)
749- return false ;
812+ return {} ;
750813
751814 uint32_t MagicWord;
752815 memcpy (&MagicWord, Magic.get (), sizeof (MagicWord));
0 commit comments