Skip to content

Commit 6afdcd3

Browse files
authored
Merge pull request #72061 from al45tair/eng/PR-123504095
[Linux][Runtime][IRGen] Mark metadata sections as retained and support section GC.
2 parents 406346b + a014bd2 commit 6afdcd3

21 files changed

+271
-101
lines changed

CMakeLists.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,8 @@ endif()
999999
# Which default linker to use. Prefer LLVM_USE_LINKER if it set, otherwise use
10001000
# our own defaults. This should only be possible in a unified (not stand alone)
10011001
# build environment.
1002+
include(GoldVersion)
1003+
10021004
if(LLVM_USE_LINKER)
10031005
set(SWIFT_USE_LINKER_default "${LLVM_USE_LINKER}")
10041006
elseif(SWIFT_HOST_VARIANT_SDK STREQUAL "ANDROID")
@@ -1010,7 +1012,17 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
10101012
elseif(DISTRO_NAME STREQUAL "Amazon Linux 2023")
10111013
set(SWIFT_USE_LINKER_default "lld")
10121014
else()
1013-
set(SWIFT_USE_LINKER_default "gold")
1015+
get_gold_version(gold_version)
1016+
if(NOT gold_version)
1017+
message(STATUS "GNU Gold not found; using lld instead")
1018+
set(SWIFT_USE_LINKER_default "lld")
1019+
elseif(gold_version VERSION_LESS "2.36")
1020+
message(STATUS "GNU Gold is too old (${gold_version}); using lld instead")
1021+
set(SWIFT_USE_LINKER_default "lld")
1022+
else()
1023+
message(STATUS "Using GNU Gold ${gold_version}")
1024+
set(SWIFT_USE_LINKER_default "gold")
1025+
endif()
10141026
endif()
10151027
set(SWIFT_USE_LINKER ${SWIFT_USE_LINKER_default} CACHE STRING
10161028
"Build Swift with a non-default linker")

cmake/modules/GoldVersion.cmake

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Find the version of ld.gold, if installed.
2+
#
3+
# Versions prior to 2.36 break Swift programs because they won't coalesce
4+
# sections with different SHF_GNU_RETAIN flags.
5+
function(get_gold_version result_var_name)
6+
find_program(gold_executable "ld.gold")
7+
if(gold_executable)
8+
execute_process(
9+
COMMAND "${gold_executable}" "--version"
10+
COMMAND "head" "-n" "1"
11+
COMMAND "sed" "-e" "s/^.* (\\([^)]*\\)).*$/\\1/g;s/.* \\([0-9][0-9]*\\(\\.[0-9][0-9]*\\)*\\).*/\\1/g"
12+
OUTPUT_VARIABLE gold_version
13+
OUTPUT_STRIP_TRAILING_WHITESPACE)
14+
set("${result_var_name}" "${gold_version}" PARENT_SCOPE)
15+
else()
16+
set("${result_var_name}" "" PARENT_SCOPE)
17+
endif()
18+
endfunction()

include/swift/RemoteInspection/ReflectionContext.h

Lines changed: 112 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -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));

lib/Driver/UnixToolChains.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,6 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job,
231231
#else
232232
Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker));
233233
#endif
234-
// Starting with lld 13, Swift stopped working with the lld --gc-sections
235-
// implementation for ELF, unless -z nostart-stop-gc is also passed to lld:
236-
//
237-
// https://reviews.llvm.org/D96914
238-
if (Linker == "lld" || (Linker.length() > 5 &&
239-
Linker.substr(Linker.length() - 6) == "ld.lld")) {
240-
Arguments.push_back("-Xlinker");
241-
Arguments.push_back("-z");
242-
Arguments.push_back("-Xlinker");
243-
Arguments.push_back("nostart-stop-gc");
244-
}
245234
}
246235

247236
// Configure the toolchain.

0 commit comments

Comments
 (0)