From 3c029ebd3fa16e1364f06fab310752d703c69c49 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 28 Feb 2024 17:00:51 +0000 Subject: [PATCH 01/15] [IRGen] Use llvm.used on ELF instead of llvm.compiler.used. We changed to `llvm.compiler.used` because of the behaviour of `gold`, which refuses to coalesce sections that have different `SHF_GNU_RETAIN` flags, which causes problems with metadata. Originally I thought we were going to have to generate two sections with distinct names and have the runtime look for both of them, but it turns out that the runtime only wants to see sections that have `SHF_GNU_RETAIN` in any case. It's really the reflection code that is interested in being able to see non-retained sections. The upshot is that we don't need to use `llvm.compiler.used`; it's just fine if we have duplicate sections, as long as the reflection code looks for them when it's inspecting an ELF image. This also means we no longer need to pass `-z nostart-stop-gc` to the linker if we're using `lld`. rdar://123504095 --- lib/Driver/UnixToolChains.cpp | 11 ----------- lib/IRGen/GenDecl.cpp | 9 --------- .../distributed_actor_accessor_section_elf.swift | 2 +- test/Driver/link-time-opt.swift | 2 -- test/IRGen/ELF-remove-autolink-section.swift | 2 +- test/IRGen/autolink_elf.swift | 3 +-- test/IRGen/objc_protocol_vars.sil | 3 +-- test/IRGen/section_asm.swift | 10 +++++----- test/IRGen/unused.sil | 2 +- test/embedded/internalize-no-stdlib.swift | 2 +- 10 files changed, 11 insertions(+), 35 deletions(-) diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp index 90afe3ec8b205..3452c1395ede1 100644 --- a/lib/Driver/UnixToolChains.cpp +++ b/lib/Driver/UnixToolChains.cpp @@ -231,17 +231,6 @@ toolchains::GenericUnix::constructInvocation(const DynamicLinkJobAction &job, #else Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); #endif - // Starting with lld 13, Swift stopped working with the lld --gc-sections - // implementation for ELF, unless -z nostart-stop-gc is also passed to lld: - // - // https://reviews.llvm.org/D96914 - if (Linker == "lld" || (Linker.length() > 5 && - Linker.substr(Linker.length() - 6) == "ld.lld")) { - Arguments.push_back("-Xlinker"); - Arguments.push_back("-z"); - Arguments.push_back("-Xlinker"); - Arguments.push_back("nostart-stop-gc"); - } } // Configure the toolchain. diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 8ac4d0a312cb9..0052c3fe2cbb7 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1035,15 +1035,6 @@ bool LinkInfo::isUsed(IRLinkage IRL) { /// /// This value must have a definition by the time the module is finalized. void IRGenModule::addUsedGlobal(llvm::GlobalValue *global) { - - // As of reviews.llvm.org/D97448 "ELF: Create unique SHF_GNU_RETAIN sections - // for llvm.used global objects" LLVM creates separate sections for globals in - // llvm.used on ELF. Therefore we use llvm.compiler.used on ELF instead. - if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF) { - addCompilerUsedGlobal(global); - return; - } - LLVMUsed.push_back(global); } diff --git a/test/Distributed/distributed_actor_accessor_section_elf.swift b/test/Distributed/distributed_actor_accessor_section_elf.swift index cbd90e42faff5..5839638940bf7 100644 --- a/test/Distributed/distributed_actor_accessor_section_elf.swift +++ b/test/Distributed/distributed_actor_accessor_section_elf.swift @@ -137,7 +137,7 @@ public distributed actor MyOtherActor { // CHECK-SAME: (ptr @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyYaKFTETFTu" to i{{32|64}}) // CHECK-SAME: , section "swift5_accessible_functions", {{.*}} -// CHECK: @llvm.compiler.used = appending global [{{.*}} x ptr] [ +// CHECK: @llvm.used = appending global [{{.*}} x ptr] [ // CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiYaKFTEHF" // CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiYaKFTEHF" // CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSYaKFTEHF" diff --git a/test/Driver/link-time-opt.swift b/test/Driver/link-time-opt.swift index 8cc918e8cd833..4d505be9b28b0 100644 --- a/test/Driver/link-time-opt.swift +++ b/test/Driver/link-time-opt.swift @@ -14,7 +14,6 @@ // CHECK-SIMPLE-THIN-linux-gnu: clang // CHECK-SIMPLE-THIN-linux-gnu-DAG: -flto=thin // CHECK-SIMPLE-THIN-linux-gnu-DAG: -fuse-ld=lld -// CHECK-SIMPLE-THIN-linux-gnu-DAG: -Xlinker -z -Xlinker nostart-stop-gc // CHECK-SIMPLE-THIN-linux-gnu-DAG: [[BITCODEFILE]] // CHECK-SIMPLE-THIN-linux-gnu-NOT: swift-autolink-extract @@ -36,7 +35,6 @@ // CHECK-SIMPLE-FULL-linux-gnu: clang // CHECK-SIMPLE-FULL-linux-gnu-DAG: -flto=full // CHECK-SIMPLE-FULL-linux-gnu-DAG: -fuse-ld=lld -// CHECK-SIMPLE-FULL-linux-gnu-DAG: -Xlinker -z -Xlinker nostart-stop-gc // CHECK-SIMPLE-FULL-linux-gnu-DAG: [[BITCODEFILE]] // CHECK-SIMPLE-FULL-linux-gnu-NOT: swift-autolink-extract diff --git a/test/IRGen/ELF-remove-autolink-section.swift b/test/IRGen/ELF-remove-autolink-section.swift index cd2ac6c74e4ec..154ef5143bed9 100644 --- a/test/IRGen/ELF-remove-autolink-section.swift +++ b/test/IRGen/ELF-remove-autolink-section.swift @@ -12,7 +12,7 @@ print("Hi from Swift!") -// ELF: @llvm.compiler.used = {{.*}}ptr @_swift1_autolink_entries +// ELF: @llvm.used = {{.*}}ptr @_swift1_autolink_entries // SECTION: .swift1_autolink_entries // NOSECTION-NOT: .swift1_autolink_entries diff --git a/test/IRGen/autolink_elf.swift b/test/IRGen/autolink_elf.swift index 54331527822a3..e276db7a8a15c 100644 --- a/test/IRGen/autolink_elf.swift +++ b/test/IRGen/autolink_elf.swift @@ -10,5 +10,4 @@ import Empty // as used. // CHECK-DAG: @_swift1_autolink_entries = private constant [26 x i8] c"-lswiftEmpty\00-lanotherLib\00", section ".swift1_autolink_entries",{{.*}} align 8 -// CHECK-DAG: @llvm.compiler.used = appending global [{{.*}} x ptr] [{{.*}}ptr @_swift1_autolink_entries{{.*}}], section "llvm.metadata" - +// CHECK-DAG: @llvm.used = appending global [{{.*}} x ptr] [{{.*}}ptr @_swift1_autolink_entries{{.*}}], section "llvm.metadata" diff --git a/test/IRGen/objc_protocol_vars.sil b/test/IRGen/objc_protocol_vars.sil index 3a455384e77a1..020bfd1194dab 100644 --- a/test/IRGen/objc_protocol_vars.sil +++ b/test/IRGen/objc_protocol_vars.sil @@ -27,6 +27,5 @@ import Foundation } // CHECK-macho: @llvm.used = appending global [{{.*}}] [{{.*}}, ptr @"\01l_OBJC_LABEL_PROTOCOL_$__TtP18objc_protocol_vars1T_", ptr @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP18objc_protocol_vars1T_", {{.*}}], {{.*}} -// CHECK-elf: @llvm.compiler.used = appending global [{{.*}}] [{{.*}}, ptr @"\01l_OBJC_LABEL_PROTOCOL_$__TtP18objc_protocol_vars1T_", ptr @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP18objc_protocol_vars1T_", {{.*}}], {{.*}} +// CHECK-elf: @llvm.used = appending global [{{.*}}] [{{.*}}, ptr @"\01l_OBJC_LABEL_PROTOCOL_$__TtP18objc_protocol_vars1T_", ptr @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP18objc_protocol_vars1T_", {{.*}}], {{.*}} // CHECK-coff: @llvm.used = appending global [{{.*}}] [{{.*}}, ptr @"\01l_OBJC_LABEL_PROTOCOL_$__TtP18objc_protocol_vars1T_", ptr @"\01l_OBJC_PROTOCOL_REFERENCE_$__TtP18objc_protocol_vars1T_", {{.*}}], {{.*}} - diff --git a/test/IRGen/section_asm.swift b/test/IRGen/section_asm.swift index 673c9ac71c09f..4e8fc08ca16ca 100644 --- a/test/IRGen/section_asm.swift +++ b/test/IRGen/section_asm.swift @@ -2,24 +2,24 @@ // REQUIRES: swift_in_compiler // UNSUPPORTED: CPU=wasm32 -// CHECK: .section{{.*}}__TEXT,__mysection +// CHECK: .section{{.*}}"__TEXT,__mysection","ax" // CHECK-NOT: .section // CHECK: $s7section3fooyyF: -// CHECK: .section{{.*}}__TEXT,__mysection +// CHECK: .section{{.*}}"__TEXT,__mysection","ax" // CHECK-NOT: .section // CHECK: $s7section8MyStructV3fooyyF: -// CHECK: .section{{.*}}__DATA,__mysection +// CHECK: .section{{.*}}"__DATA,__mysection","aw" // CHECK-NOT: .section // CHECK: $s7section2g0Sivp: // CHECK-NOT: .section // CHECK: $s7section2g1Si_Sitvp: // CHECK-NOT: .section // CHECK: $s7section2g2Sbvp: -// CHECK-NOT: .section +// CHECK: .section{{.*}}"__DATA,__mysection","awR" // CHECK: $s7section2g3Sbvp: -// CHECK-NOT: .section +// CHECK: .section{{.*}}"__DATA,__mysection","aw" // CHECK: $s7section2g4SpySiGSgvp: // CHECK-NOT: .section // CHECK: $s7section2g5SpySiGSgvp: diff --git a/test/IRGen/unused.sil b/test/IRGen/unused.sil index a03a3dad630ef..6802916f301d0 100644 --- a/test/IRGen/unused.sil +++ b/test/IRGen/unused.sil @@ -56,7 +56,7 @@ bb0(%0 : $Int32, %1 : $UnsafeMutablePointer> // CHECK-elf: @"\01l_entry_point" = private constant { i32, i32 } { i32 trunc (i64 sub (i64 ptrtoint (ptr @main to i64), i64 ptrtoint (ptr @"\01l_entry_point" to i64)) to i32), i32 0 }, section "swift5_entry", align 4 // CHECK-macho: @llvm.used = appending global [4 x ptr] [ptr @frieda, ptr @main, ptr @"\01l_entry_point", ptr @__swift_reflection_version], section "llvm.metadata" -// CHECK-elf: @llvm.compiler.used = appending global [5 x ptr] [ptr @frieda, ptr @main, ptr @"\01l_entry_point", ptr @__swift_reflection_version, ptr @_swift1_autolink_entries], section "llvm.metadata" +// CHECK-elf: @llvm.used = appending global [5 x ptr] [ptr @frieda, ptr @main, ptr @"\01l_entry_point", ptr @__swift_reflection_version, ptr @_swift1_autolink_entries], section "llvm.metadata" // CHECK: define linkonce_odr hidden swiftcc void @qux() // CHECK: define hidden swiftcc void @fred() diff --git a/test/embedded/internalize-no-stdlib.swift b/test/embedded/internalize-no-stdlib.swift index 97d5d4662b77c..8473d2352d202 100644 --- a/test/embedded/internalize-no-stdlib.swift +++ b/test/embedded/internalize-no-stdlib.swift @@ -26,7 +26,7 @@ public func main() { } // CHECK-ELF: @_swift1_autolink_entries = -// CHECK-ELF: @llvm.compiler.used = appending global [1 x ptr] [ptr @_swift1_autolink_entries], section "llvm.metadata" +// CHECK-ELF: @llvm.used = appending global [1 x ptr] [ptr @_swift1_autolink_entries], section "llvm.metadata" // CHECK-ELF-NOT: @llvm.used // CHECK-MACHO-NOT: @llvm.compiler.used From b7557247a7ab2fd7cdba5c37802fff3f87924f22 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:34:42 +0000 Subject: [PATCH 02/15] [Runtime] Tidy up section declarations slightly. This also calls out the reflection sections, even though we don't actually need to do anything special for them (as it turns out). rdar://123504095 --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 37 ++++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index b83a570631c48..9e726920baeb0 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -36,32 +36,43 @@ static const void *__backtraceRef __attribute__((used)) // by the linker. Otherwise, we may end up with undefined symbol references as // the linker table section was never constructed. #if defined(__ELF__) -# define DECLARE_EMPTY_METADATA_SECTION(name) __asm__("\t.section " #name ",\"a\"\n"); +# define DECLARE_EMPTY_METADATA_SECTION(name,attrs) __asm__("\t.section " #name ",\"" attrs "\"\n"); #elif defined(__wasm__) -# define DECLARE_EMPTY_METADATA_SECTION(name) __asm__("\t.section " #name ",\"R\",@\n"); +# define DECLARE_EMPTY_METADATA_SECTION(name,attrs) __asm__("\t.section " #name ",\"R\",@\n"); #endif -#define DECLARE_SWIFT_SECTION(name) \ - DECLARE_EMPTY_METADATA_SECTION(name) \ - __attribute__((__visibility__("hidden"),__aligned__(1))) extern const char __start_##name; \ - __attribute__((__visibility__("hidden"),__aligned__(1))) extern const char __stop_##name; +#define BOUNDS_VISIBILITY __attribute__((__visibility__("hidden"),__aligned__(1))) +#define DECLARE_BOUNDS(name) \ + BOUNDS_VISIBILITY extern const char __start_##name; \ + BOUNDS_VISIBILITY extern const char __stop_##name; + +#define DECLARE_SWIFT_SECTION(name) \ + DECLARE_EMPTY_METADATA_SECTION(name,"aR") \ + DECLARE_BOUNDS(name) + +// These may or may not be present, depending on compiler switches; it's +// worth calling them out as a result. +#define DECLARE_SWIFT_REFLECTION_SECTION(name) \ + DECLARE_SWIFT_SECTION(name) extern "C" { DECLARE_SWIFT_SECTION(swift5_protocols) DECLARE_SWIFT_SECTION(swift5_protocol_conformances) DECLARE_SWIFT_SECTION(swift5_type_metadata) -DECLARE_SWIFT_SECTION(swift5_typeref) -DECLARE_SWIFT_SECTION(swift5_reflstr) -DECLARE_SWIFT_SECTION(swift5_fieldmd) -DECLARE_SWIFT_SECTION(swift5_assocty) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_fieldmd) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_builtin) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_assocty) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_capture) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_reflstr) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_typeref) +DECLARE_SWIFT_REFLECTION_SECTION(swift5_mpenum) + DECLARE_SWIFT_SECTION(swift5_replace) DECLARE_SWIFT_SECTION(swift5_replac2) -DECLARE_SWIFT_SECTION(swift5_builtin) -DECLARE_SWIFT_SECTION(swift5_capture) -DECLARE_SWIFT_SECTION(swift5_mpenum) DECLARE_SWIFT_SECTION(swift5_accessible_functions) DECLARE_SWIFT_SECTION(swift5_runtime_attributes) + DECLARE_SWIFT_SECTION(swift5_tests) } From c9dcee2774ea9512c010d959adcbe57d26093b65 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:36:14 +0000 Subject: [PATCH 03/15] [RemoteInspection] Update ReflectionContext to cope with multiple sections. When linking with `gold`, we can end up with two separate sections for each of the reflection sections; this happens because `swiftrt.o` declares them with `SHF_GNU_RETAIN` set (to stop them from vanishing when section GC is enabled), but if the compiler is set to allow the reflection information to be stripped then *it* will generate them *without* `SHF_GNU_RETAIN`. The other Linux linkers will coalesce the two sections and leave the `SHF_GNU_RETAIN` flag set, but `gold` does not, and adds both of them separately to the output. The upshot is that we want `ReflectionContext` to look for both the retained and non-retained sections and read the data from both of them. rdar://123504095 --- .../RemoteInspection/ReflectionContext.h | 104 +++++++++++++----- 1 file changed, 77 insertions(+), 27 deletions(-) diff --git a/include/swift/RemoteInspection/ReflectionContext.h b/include/swift/RemoteInspection/ReflectionContext.h index 178152ef35b87..dffc4d355cf26 100644 --- a/include/swift/RemoteInspection/ReflectionContext.h +++ b/include/swift/RemoteInspection/ReflectionContext.h @@ -601,7 +601,7 @@ class ReflectionContext auto StrTab = reinterpret_cast(StrTabBuf); bool Error = false; auto findELFSectionByName = - [&](llvm::StringRef Name) -> std::pair, uint64_t> { + [&](llvm::StringRef Name, bool Retained) -> std::pair, uint64_t> { if (Error) return {nullptr, 0}; // Now for all the sections, find their name. @@ -616,6 +616,8 @@ class ReflectionContext std::string SecName(Start, StringSize); if (SecName != Name) continue; + if (Retained != !!(Hdr->sh_flags & llvm::ELF::SHF_GNU_RETAIN)) + continue; RemoteAddress SecStart = RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); auto SecSize = Hdr->sh_size; @@ -649,48 +651,96 @@ class ReflectionContext SwiftObjectFileFormatELF ObjectFileFormat; auto FieldMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd), true); auto AssocTySec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty), true); auto BuiltinTySec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin), true); auto CaptureSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::capture)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture), true); auto TypeRefMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref), true); auto ReflStrMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr), true); auto ConformMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::conform)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::conform), true); auto MPEnumMdSec = findELFSectionByName( - ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum)); + ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), true); if (Error) return false; + std::optional result = false; + // We succeed if at least one of the sections is present in the // ELF executable. - if (FieldMdSec.first == nullptr && - AssocTySec.first == nullptr && - BuiltinTySec.first == nullptr && - CaptureSec.first == nullptr && - TypeRefMdSec.first == nullptr && - ReflStrMdSec.first == nullptr && - ConformMdSec.first == nullptr && - MPEnumMdSec.first == nullptr) + if (FieldMdSec.first != nullptr || + AssocTySec.first != nullptr || + BuiltinTySec.first != nullptr || + CaptureSec.first != nullptr || + TypeRefMdSec.first != nullptr || + ReflStrMdSec.first != nullptr || + ConformMdSec.first != nullptr || + MPEnumMdSec.first != nullptr) { + ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, + {AssocTySec.first, AssocTySec.second}, + {BuiltinTySec.first, BuiltinTySec.second}, + {CaptureSec.first, CaptureSec.second}, + {TypeRefMdSec.first, TypeRefMdSec.second}, + {ReflStrMdSec.first, ReflStrMdSec.second}, + {ConformMdSec.first, ConformMdSec.second}, + {MPEnumMdSec.first, MPEnumMdSec.second}, + PotentialModuleNames}; + result = this->addReflectionInfo(info); + } + + // Also check for the non-retained versions of the sections; we'll + // only return a single reflection info ID if both are found (and it'll + // be the one for the retained sections if we have them), but we'll + // still add all the reflection information. + FieldMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::fieldmd), false); + AssocTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::assocty), false); + BuiltinTySec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::builtin), false); + CaptureSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::capture), false); + TypeRefMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::typeref), false); + ReflStrMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::reflstr), false); + ConformMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::conform), false); + MPEnumMdSec = findELFSectionByName( + ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), false); + + if (Error) return false; - ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, - {AssocTySec.first, AssocTySec.second}, - {BuiltinTySec.first, BuiltinTySec.second}, - {CaptureSec.first, CaptureSec.second}, - {TypeRefMdSec.first, TypeRefMdSec.second}, - {ReflStrMdSec.first, ReflStrMdSec.second}, - {ConformMdSec.first, ConformMdSec.second}, - {MPEnumMdSec.first, MPEnumMdSec.second}, - PotentialModuleNames}; + if (FieldMdSec.first != nullptr || + AssocTySec.first != nullptr || + BuiltinTySec.first != nullptr || + CaptureSec.first != nullptr || + TypeRefMdSec.first != nullptr || + ReflStrMdSec.first != nullptr || + ConformMdSec.first != nullptr || + MPEnumMdSec.first != nullptr) { + ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, + {AssocTySec.first, AssocTySec.second}, + {BuiltinTySec.first, BuiltinTySec.second}, + {CaptureSec.first, CaptureSec.second}, + {TypeRefMdSec.first, TypeRefMdSec.second}, + {ReflStrMdSec.first, ReflStrMdSec.second}, + {ConformMdSec.first, ConformMdSec.second}, + {MPEnumMdSec.first, MPEnumMdSec.second}, + PotentialModuleNames}; + auto rid = this->addReflectionInfo(info); + if (!result) + result = rid; + } - return this->addReflectionInfo(info); + return result; } /// Parses metadata information from an ELF image. Because the Section From 0a5653dbaf03c21e175d317a5344e446c64a4ef0 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:42:35 +0000 Subject: [PATCH 04/15] [IRGen] When creating a module object, mark `__Swift_AST` as used. Without doing this, `__Swift_AST` gets stripped from the output. We also need to call `IGM.finalize()` before `::performLLVM()` in the `createSwiftModuleObjectFile()` function, so that we update the section to mark it as retained. rdar://123504095 --- lib/IRGen/IRGen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index b7cdf8bc46fcd..8729410c5d365 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -1663,8 +1663,10 @@ void swift::createSwiftModuleObjectFile(SILModule &SILMod, StringRef Buffer, break; } } + IGM.addUsedGlobal(ASTSym); ASTSym->setSection(Section); ASTSym->setAlignment(llvm::MaybeAlign(serialization::SWIFTMODULE_ALIGNMENT)); + IGM.finalize(); ::performLLVM(Opts, Ctx.Diags, nullptr, nullptr, IGM.getModule(), IGM.TargetMachine.get(), OutputPath, Ctx.getOutputBackend(), Ctx.Stats); From a3637194343b3cc178ea02da9ccd592fc2d85e3b Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:45:52 +0000 Subject: [PATCH 05/15] [IRGen] Set `TargetOpts.UseInitArray` in `getIRTargetOptions()`. IRGen sets up the `llvm::TargetOptions` by itself, rather than copying them from the Clang instance (it has to do this, at present, because Clang doesn't provide a way to get it to initialise one). Unfortunately, it didn't set `UseInitArray`, which when linking with GNU `ld` or `gold` is *fine* because those linkers automatically convert `.ctors` and `.dtors` sections into `.init_array` and `.fini_array` respectively. *However*, `lld` does *not* do this conversion, so when using `lld`, if the compiler generates a constructor or destructor function, it won't be called(!) The fix is to set `UseInitArray` properly; I chose to copy the setting from Clang, just in case Clang knows of a reason why it shouldn't be `true`. rdar://123504095 --- lib/IRGen/IRGen.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 8729410c5d365..118a634d01509 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -138,6 +138,9 @@ swift::getIRTargetOptions(const IRGenOptions &Opts, ASTContext &Ctx) { auto *Clang = static_cast(Ctx.getClangModuleLoader()); + // Set UseInitArray appropriately. + TargetOpts.UseInitArray = Clang->getCodeGenOpts().UseInitArray; + // WebAssembly doesn't support atomics yet, see // https://github.com/apple/swift/issues/54533 for more details. if (Clang->getTargetInfo().getTriple().isOSBinFormatWasm()) From 8ba1d983542a3743c95cc3463e7af3dcaaeb64f3 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:50:00 +0000 Subject: [PATCH 06/15] [Test] Fix function_sections test to support different linkers. `gold` and `lld` produce map files in different formats; this test can and should work for both of them. rdar://123504095 --- test/LinkerSections/function_sections.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/LinkerSections/function_sections.swift b/test/LinkerSections/function_sections.swift index a2cf2a39a5c34..f941adec11a39 100644 --- a/test/LinkerSections/function_sections.swift +++ b/test/LinkerSections/function_sections.swift @@ -1,10 +1,13 @@ // REQUIRES: OS=linux-gnu || OS=freebsd // RUN: %empty-directory(%t) // RUN: %target-build-swift -Xfrontend -function-sections -emit-module -emit-library -static -parse-stdlib %S/Inputs/FunctionSections.swift -// RUN: %target-build-swift -Xlinker --gc-sections -Xlinker -Map=%t/../../FunctionSections.map -I%t/../.. -L%t/../.. -lFunctionSections %S/Inputs/FunctionSectionsUse.swift -// RUN: %FileCheck %s < %t/../../FunctionSections.map +// RUN: %target-build-swift -Xlinker -v -Xlinker --gc-sections -Xlinker -Map=%t/../../FunctionSections.map -I%t/../.. -L%t/../.. -lFunctionSections %S/Inputs/FunctionSectionsUse.swift 2>&1 | sed 's/.*\(gold\|LLD\).*/\1/g' | tr "[:lower:]" "[:upper:]" > %t/../../Linker.txt +// RUN: %FileCheck --check-prefix $(cat %t/../../Linker.txt) %s < %t/../../FunctionSections.map -// CHECK: Discarded input sections -// CHECK: .text.$s16FunctionSections5func2yyF -// CHECK: Memory map -// CHECK: .text.$s16FunctionSections5func1yyF +// GOLD: Discarded input sections +// GOLD: .text.$s16FunctionSections5func2yyF +// GOLD: Memory map +// GOLD: .text.$s16FunctionSections5func1yyF + +// LLD: .text.$s16FunctionSections5func1yyF +// LLD-NOT: .text.$s16FunctionSections5func2yyF From f9ec4793e9b04a94b4210514456696eedc21f9ae Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 4 Mar 2024 16:51:10 +0000 Subject: [PATCH 07/15] [Test] Add linker_overridden feature. When testing different linkers, it's sometimes useful to run the tests with `SWIFT_DRIVER_TEST_OPTIONS=" -use-ld="`. If we do this, it will break a handful of tests because they expect the compiler driver to choose an appropriate linker automatically. To avoid having these fail, detect when someone has done this, and set a new feature, `linker_overridden`, then mark the tests in question with `UNSUPPORTED: linker_overridden`. rdar://123504095 --- test/Driver/link-time-opt.swift | 2 ++ test/Driver/static-archive.swift | 2 ++ test/Interpreter/llvm_link_time_opt.swift | 2 ++ test/embedded/once.swift | 1 + test/lit.cfg | 5 +++++ 5 files changed, 12 insertions(+) diff --git a/test/Driver/link-time-opt.swift b/test/Driver/link-time-opt.swift index 4d505be9b28b0..78fe69495e77c 100644 --- a/test/Driver/link-time-opt.swift +++ b/test/Driver/link-time-opt.swift @@ -1,3 +1,5 @@ +// UNSUPPORTED: linker_overridden + // RUN: %swiftc_driver -driver-print-jobs %S/../Inputs/empty.swift -lto=llvm-thin -target x86_64-unknown-linux-gnu | %FileCheck %s --check-prefix=CHECK-SIMPLE-THIN --check-prefix=CHECK-SIMPLE-THIN-linux-gnu // RUN: %swiftc_driver -driver-print-jobs %S/../Inputs/empty.swift -lto=llvm-thin -target x86_64-unknown-windows-msvc | %FileCheck %s --check-prefix=CHECK-SIMPLE-THIN --check-prefix=CHECK-SIMPLE-THIN-windows-msvc diff --git a/test/Driver/static-archive.swift b/test/Driver/static-archive.swift index f2b7dbfc3d1c8..88bc477fb5845 100644 --- a/test/Driver/static-archive.swift +++ b/test/Driver/static-archive.swift @@ -1,3 +1,5 @@ +// UNSUPPORTED: linker_overridden + // RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.9 -emit-library %s -module-name ARCHIVER -static 2>&1 | %FileCheck -check-prefix CHECK-MACOS %s // CHECK-MACOS: swift diff --git a/test/Interpreter/llvm_link_time_opt.swift b/test/Interpreter/llvm_link_time_opt.swift index 7f60f66770109..04a602236ee6e 100644 --- a/test/Interpreter/llvm_link_time_opt.swift +++ b/test/Interpreter/llvm_link_time_opt.swift @@ -10,6 +10,8 @@ // loaded too late"). // REQUIRES: no_asan +// UNSUPPORTED: linker_overridden + // RUN: %empty-directory(%t) // RUN: %use_just_built_liblto %target-swiftc_driver -emit-library -static -lto=llvm-full %lto_flags -emit-module %S/Inputs/lto/module1.swift -working-directory %t // RUN: %use_just_built_liblto %target-swiftc_driver -lto=llvm-full %lto_flags %s -I%t -L%t -lmodule1 -module-name main -o %t/main diff --git a/test/embedded/once.swift b/test/embedded/once.swift index 4291fa4cfd9ab..3a21f9a7ca112 100644 --- a/test/embedded/once.swift +++ b/test/embedded/once.swift @@ -6,6 +6,7 @@ // REQUIRES: executable_test // REQUIRES: optimized_stdlib // REQUIRES: OS=macosx || OS=linux-gnu +// UNSUPPORTED: linker_overridden // For LTO, the linker dlopen()'s the libLTO library, which is a scenario that // ASan cannot work in ("Interceptors are not working, AddressSanitizer is diff --git a/test/lit.cfg b/test/lit.cfg index c372541a50477..dbb5d9ff56cde 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -547,6 +547,11 @@ config.swift_driver_test_options += os.environ.get('SWIFT_DRIVER_TEST_OPTIONS', config.swift_ide_test_test_options += os.environ.get('SWIFT_IDE_TEST_TEST_OPTIONS', '') config.sil_test_options = os.environ.get('SIL_TEST_OPTIONS', '') +# Check if we overrode the linker; if we do, set a feature to say that, which +# lets us disable tests that rely on the driver choosing the linker. +if re.search(r'(?:^|[ \t])-use-ld=[^ \t]*', config.swift_driver_test_options): + config.available_features.add('linker_overridden') + config.clang_module_cache_path = make_path(config.swift_test_results_dir, "clang-module-cache") shutil.rmtree(config.clang_module_cache_path, ignore_errors=True) mcp_opt = "-module-cache-path %s" % shell_quote(config.clang_module_cache_path) From cb4fd88ece9c3da7fd623e758bec7d5091309079 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 5 Mar 2024 12:23:24 +0000 Subject: [PATCH 08/15] [RemoteInspection] Use `bool` instead of `!!`. Since this is adjacent to a `!=` operator, explicitly using `bool` seems clearer. Co-authored-by: Evan Wilde --- include/swift/RemoteInspection/ReflectionContext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/swift/RemoteInspection/ReflectionContext.h b/include/swift/RemoteInspection/ReflectionContext.h index dffc4d355cf26..33ed3cf91c049 100644 --- a/include/swift/RemoteInspection/ReflectionContext.h +++ b/include/swift/RemoteInspection/ReflectionContext.h @@ -616,7 +616,7 @@ class ReflectionContext std::string SecName(Start, StringSize); if (SecName != Name) continue; - if (Retained != !!(Hdr->sh_flags & llvm::ELF::SHF_GNU_RETAIN)) + if (Retained != bool(Hdr->sh_flags & llvm::ELF::SHF_GNU_RETAIN)) continue; RemoteAddress SecStart = RemoteAddress(ImageStart.getAddressData() + Hdr->sh_addr); From 9d9c123858e71662c366ffd24b1490ca12154efa Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 5 Mar 2024 14:36:37 +0000 Subject: [PATCH 09/15] [Test] Update section_asm to work on non-ELF platforms again. On ELF platforms, the output will be slightly different to non-ELF platforms. The test should ideally run everywhere, however, so we need to be able to distinguish these platforms by changing the lit.cfg to add some extra variables. rdar://123504095 --- test/IRGen/section_asm.swift | 37 +++++++++++++++++++++++++++------ test/lit.cfg | 40 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/test/IRGen/section_asm.swift b/test/IRGen/section_asm.swift index 4e8fc08ca16ca..4f8706aa8416c 100644 --- a/test/IRGen/section_asm.swift +++ b/test/IRGen/section_asm.swift @@ -1,27 +1,52 @@ -// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %S/section.swift -S -parse-as-library | %FileCheck %s +// RUN: %target-swift-frontend -enable-experimental-feature SymbolLinkageMarkers -primary-file %S/section.swift -S -parse-as-library | %FileCheck --check-prefix CHECK%target-os-binfmt-elf %s + // REQUIRES: swift_in_compiler // UNSUPPORTED: CPU=wasm32 -// CHECK: .section{{.*}}"__TEXT,__mysection","ax" +// CHECK: .section{{.*}}__TEXT,__mysection // CHECK-NOT: .section // CHECK: $s7section3fooyyF: -// CHECK: .section{{.*}}"__TEXT,__mysection","ax" +// CHECK: .section{{.*}}__TEXT,__mysection // CHECK-NOT: .section // CHECK: $s7section8MyStructV3fooyyF: -// CHECK: .section{{.*}}"__DATA,__mysection","aw" +// CHECK: .section{{.*}}__DATA,__mysection // CHECK-NOT: .section // CHECK: $s7section2g0Sivp: // CHECK-NOT: .section // CHECK: $s7section2g1Si_Sitvp: // CHECK-NOT: .section // CHECK: $s7section2g2Sbvp: -// CHECK: .section{{.*}}"__DATA,__mysection","awR" +// CHECK-NOT: .section // CHECK: $s7section2g3Sbvp: -// CHECK: .section{{.*}}"__DATA,__mysection","aw" +// CHECK-NOT: .section // CHECK: $s7section2g4SpySiGSgvp: // CHECK-NOT: .section // CHECK: $s7section2g5SpySiGSgvp: // CHECK-NOT: .section // CHECK: $s7section8MyStructV7static0SivpZ: + +// CHECKELF: .section{{.*}}"__TEXT,__mysection","ax" +// CHECKELF-NOT: .section +// CHECKELF: $s7section3fooyyF: + +// CHECKELF: .section{{.*}}"__TEXT,__mysection","ax" +// CHECKELF-NOT: .section +// CHECKELF: $s7section8MyStructV3fooyyF: + +// CHECKELF: .section{{.*}}"__DATA,__mysection","aw" +// CHECKELF-NOT: .section +// CHECKELF: $s7section2g0Sivp: +// CHECKELF-NOT: .section +// CHECKELF: $s7section2g1Si_Sitvp: +// CHECKELF-NOT: .section +// CHECKELF: $s7section2g2Sbvp: +// CHECKELF: .section{{.*}}"__DATA,__mysection","awR" +// CHECKELF: $s7section2g3Sbvp: +// CHECKELF: .section{{.*}}"__DATA,__mysection","aw" +// CHECKELF: $s7section2g4SpySiGSgvp: +// CHECKELF-NOT: .section +// CHECKELF: $s7section2g5SpySiGSgvp: +// CHECKELF-NOT: .section +// CHECKELF: $s7section8MyStructV7static0SivpZ: diff --git a/test/lit.cfg b/test/lit.cfg index dbb5d9ff56cde..d5651d4b6425b 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -1032,6 +1032,46 @@ if run_os in ( ): target_mandates_stable_abi = "TRUE" config.available_features.add('swift_only_stable_abi') + +if run_os in ('macosx', 'ios', 'maccatalyst', 'tvos', 'watchos', 'xros'): + target_os_family = 'DARWIN' + target_os_binfmt = 'MACH-O' +elif run_os in ('windows-cygnus', 'windows-gnu', 'windows-msvc'): + target_os_family = 'WINDOWS' + target_os_binfmt = 'PE-COFF' +elif run_os in ('linux-gnu', 'linux-gnueabihf', 'linux-android', 'linux-androideabi'): + target_os_family = 'LINUX' + target_os_binfmt = 'ELF' +elif run_os in ('freebsd', 'openbsd'): + target_os_family = 'BSD' + target_os_binfmt = 'ELF' +else: + target_os_family = 'UNKNOWN' + target_os_binfmt = 'UNKNOWN' + +config.available_features.add('OS_FAMILY={}'.format(target_os_family.lower())) +config.available_features.add('OS_BINFMT={}'.format(target_os_binfmt.lower())) + +for family in ('DARWIN', 'WINDOWS', 'LINUX', 'BSD', 'UNKNOWN'): + if family == target_os_family: + subst = family + else: + subst = "" + config.substitutions.append( + ('%target-os-family-{}'.format(family.lower()), subst) + ) +config.substitutions.append(('%target-os-family', target_os_family)) + +for binfmt in ('MACH-O', 'PE-COFF', 'ELF', 'UNKNOWN'): + if binfmt == target_os_binfmt: + subst = binfmt + else: + subst = "" + config.substitutions.append( + ('%target-os-binfmt-{}'.format(binfmt.lower()), subst) + ) +config.substitutions.append(('%target-os-binfmt', target_os_binfmt)) + config.substitutions.append(('%target-os-abi', target_os_abi)) config.substitutions.append(('%target-os-is-maccatalyst', target_os_is_maccatalyst)) config.substitutions.append(('%target-mandates-stable-abi', From bc64f6df9fede7cedf76b947b7cd19f52881eef0 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Tue, 5 Mar 2024 14:57:56 +0000 Subject: [PATCH 10/15] [RemoteInspection] Add a big comment to ReflectionContext.h. Add a comment to ReflectionContext.h explaining the situation regarding `SHF_GNU_RETAIN` and the reflection metadata sections. rdar://123504095 --- .../RemoteInspection/ReflectionContext.h | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/swift/RemoteInspection/ReflectionContext.h b/include/swift/RemoteInspection/ReflectionContext.h index 33ed3cf91c049..e3e42b1eb1e77 100644 --- a/include/swift/RemoteInspection/ReflectionContext.h +++ b/include/swift/RemoteInspection/ReflectionContext.h @@ -600,6 +600,29 @@ class ReflectionContext return false; auto StrTab = reinterpret_cast(StrTabBuf); bool Error = false; + + // GNU ld and lld both merge sections regardless of the + // `SHF_GNU_RETAIN` flag. gold, presently, does not. The Swift + // compiler has a couple of switches that control whether or not + // the reflection sections are stripped; when these are enabled, + // it will _not_ set `SHF_GNU_RETAIN` on the reflection metadata + // sections. However, `swiftrt.o` contains declarations of the + // sections _with_ the `SHF_GNU_RETAIN` flag set, which makes + // sense since at runtime we will only expect to be able to access + // reflection metadata that we said we wanted to exist at runtime. + // + // The upshot is that when linking with gold, we can end up with + // two sets of reflection metadata sections. In a normal build + // where the compiler flags are the same for every linked object, + // we'll have *either* all retained *or* all un-retained sections + // (the retained sections will still exist because of `swiftrt.o`, + // but will be empty). The only time we'd expect to have a mix is + // where some code was compiled with a different setting of the + // metadata stripping flags. If that happens, the code below will + // simply add both sets of reflection sections, with the retained + // ones added first. + // + // See also https://sourceware.org/bugzilla/show_bug.cgi?id=31415. auto findELFSectionByName = [&](llvm::StringRef Name, bool Retained) -> std::pair, uint64_t> { if (Error) From 554c402f118a891e310b8f4ea5625cc020158a67 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Wed, 6 Mar 2024 18:42:10 +0000 Subject: [PATCH 11/15] [Runtime] Add the `retain` attribute to make the backtracer work. Without `retain` here, we might remove the reference that pulls in the backtracing support code. rdar://123504095 --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index 9e726920baeb0..6380695909cd5 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -28,7 +28,7 @@ static constexpr const void *__dso_handle = nullptr; #if SWIFT_ENABLE_BACKTRACING // Drag in a symbol from the backtracer, to force the static linker to include // the code. -static const void *__backtraceRef __attribute__((used)) +static const void *__backtraceRef __attribute__((used, retain)) = (const void *)swift::runtime::backtrace::_swift_backtrace_isThunkFunction; #endif From 7698836ecc743db02ecac9a15dc6875b727b0710 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Thu, 7 Mar 2024 12:55:35 +0000 Subject: [PATCH 12/15] [Test][SourceKit] Use the *builder*'s swiftrt.o when in hosttools. We were linking with the newly built `swiftrt.o` when in hosttools mode, which is wrong because the newly built `swiftrt.o` does not match the compiler we were using for the `SwiftCompilerSources`. This manifests as a failure in `SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift` because `self is ForwardingInstruction` fails as we can't find the protocol conformance records. rdar://123504095 --- tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake index 58baab5b58122..8ec08a0ca2bf2 100644 --- a/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake +++ b/tools/SourceKit/cmake/modules/AddSwiftSourceKit.cmake @@ -115,11 +115,14 @@ function(add_sourcekit_swift_runtime_link_flags target path HAS_SWIFT_MODULES) else() set(host_lib_dir "${SWIFTLIB_DIR}/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_LIB_SUBDIR}") endif() + set(host_lib_arch_dir "${host_lib_dir}/${SWIFT_HOST_VARIANT_ARCH}") + set(swiftrt "${host_lib_arch_dir}/swiftrt${CMAKE_C_OUTPUT_EXTENSION}") target_link_libraries(${target} PRIVATE ${swiftrt}) target_link_libraries(${target} PRIVATE "swiftCore") target_link_directories(${target} PRIVATE ${host_lib_dir}) + target_link_directories(${target} PRIVATE ${host_lib_arch_dir}) file(RELATIVE_PATH relative_rtlib_path "${path}" "${SWIFTLIB_DIR}/${SWIFT_SDK_${SWIFT_HOST_VARIANT_SDK}_LIB_SUBDIR}") list(APPEND RPATH_LIST "$ORIGIN/${relative_rtlib_path}") From 7df249b67cf5aec4b1baa8dc884ca0eaaa96d99c Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 8 Mar 2024 14:35:19 +0000 Subject: [PATCH 13/15] [Runtime] Tidy up a couple of minor nits. This doesn't change any code, just makes things look slightly neater. rdar://123504095 --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index 6380695909cd5..032a97cd442e4 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -36,18 +36,20 @@ static const void *__backtraceRef __attribute__((used, retain)) // by the linker. Otherwise, we may end up with undefined symbol references as // the linker table section was never constructed. #if defined(__ELF__) -# define DECLARE_EMPTY_METADATA_SECTION(name,attrs) __asm__("\t.section " #name ",\"" attrs "\"\n"); +# define DECLARE_EMPTY_METADATA_SECTION(name, attrs) __asm__("\t.section " #name ",\"" attrs "\"\n"); #elif defined(__wasm__) -# define DECLARE_EMPTY_METADATA_SECTION(name,attrs) __asm__("\t.section " #name ",\"R\",@\n"); +# define DECLARE_EMPTY_METADATA_SECTION(name, attrs) __asm__("\t.section " #name ",\"R\",@\n"); #endif -#define BOUNDS_VISIBILITY __attribute__((__visibility__("hidden"),__aligned__(1))) +#define BOUNDS_VISIBILITY __attribute__((__visibility__("hidden"), \ + __aligned__(1))) + #define DECLARE_BOUNDS(name) \ BOUNDS_VISIBILITY extern const char __start_##name; \ BOUNDS_VISIBILITY extern const char __stop_##name; #define DECLARE_SWIFT_SECTION(name) \ - DECLARE_EMPTY_METADATA_SECTION(name,"aR") \ + DECLARE_EMPTY_METADATA_SECTION(name, "aR") \ DECLARE_BOUNDS(name) // These may or may not be present, depending on compiler switches; it's From f5b1ef77a6a330e29e3d1cf71332daeb19d40473 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Fri, 8 Mar 2024 14:36:09 +0000 Subject: [PATCH 14/15] [RemoteInspection] Change "return false" to "return {}". There are a number of instances in `ReflectionContext.h` where we are doing `return false` with an `std::optional<...>` where it seems we really mean to return an empty optional instead. (The way to do this is either `return {}` or `return std::nullopt`.) rdar://123504095 --- .../RemoteInspection/ReflectionContext.h | 68 ++++++++----------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/include/swift/RemoteInspection/ReflectionContext.h b/include/swift/RemoteInspection/ReflectionContext.h index e3e42b1eb1e77..07c9982030e89 100644 --- a/include/swift/RemoteInspection/ReflectionContext.h +++ b/include/swift/RemoteInspection/ReflectionContext.h @@ -242,7 +242,7 @@ class ReflectionContext auto Buf = this->getReader().readBytes(ImageStart, sizeof(typename T::Header)); if (!Buf) - return false; + return {}; auto Header = reinterpret_cast(Buf.get()); assert(Header->magic == T::MagicNumber && "invalid MachO file"); @@ -262,7 +262,7 @@ class ReflectionContext RemoteAddress(CmdStartAddress.getAddressData() + Offset), SegmentCmdHdrSize); if (!CmdBuf) - return false; + return {}; auto CmdHdr = reinterpret_cast(CmdBuf.get()); if (strncmp(CmdHdr->segname, "__TEXT", sizeof(CmdHdr->segname)) == 0) { TextCommand = CmdHdr; @@ -274,7 +274,7 @@ class ReflectionContext // No __TEXT segment, bail out. if (!TextCommand) - return false; + return {}; // Find the load command offset. auto loadCmdOffset = ImageStart.getAddressData() + Offset + sizeof(typename T::Header); @@ -284,7 +284,7 @@ class ReflectionContext auto LoadCmdBuf = this->getReader().readBytes( RemoteAddress(LoadCmdAddress), sizeof(typename T::SegmentCmd)); if (!LoadCmdBuf) - return false; + return {}; auto LoadCmd = reinterpret_cast(LoadCmdBuf.get()); // The sections start immediately after the load command. @@ -294,7 +294,7 @@ class ReflectionContext auto Sections = this->getReader().readBytes( RemoteAddress(SectAddress), NumSect * sizeof(typename T::Section)); if (!Sections) - return false; + return {}; auto Slide = ImageStart.getAddressData() - TextCommand->vmaddr; auto SectionsBuf = reinterpret_cast(Sections.get()); @@ -346,7 +346,7 @@ class ReflectionContext ReflStrMdSec.first == nullptr && ConformMdSec.first == nullptr && MPEnumMdSec.first == nullptr) - return false; + return {}; ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, @@ -371,7 +371,7 @@ class ReflectionContext RemoteAddress(CmdStartAddress.getAddressData() + Offset), SegmentCmdHdrSize); if (!CmdBuf) - return false; + return {}; auto CmdHdr = reinterpret_cast(CmdBuf.get()); // Look for any segment name starting with __DATA or __AUTH. if (strncmp(CmdHdr->segname, "__DATA", 6) == 0 || @@ -398,7 +398,7 @@ class ReflectionContext auto DOSHdrBuf = this->getReader().readBytes( ImageStart, sizeof(llvm::object::dos_header)); if (!DOSHdrBuf) - return false; + return {}; auto DOSHdr = reinterpret_cast(DOSHdrBuf.get()); auto COFFFileHdrAddr = ImageStart.getAddressData() + @@ -408,7 +408,7 @@ class ReflectionContext auto COFFFileHdrBuf = this->getReader().readBytes( RemoteAddress(COFFFileHdrAddr), sizeof(llvm::object::coff_file_header)); if (!COFFFileHdrBuf) - return false; + return {}; auto COFFFileHdr = reinterpret_cast( COFFFileHdrBuf.get()); @@ -419,7 +419,7 @@ class ReflectionContext RemoteAddress(SectionTableAddr), sizeof(llvm::object::coff_section) * COFFFileHdr->NumberOfSections); if (!SectionTableBuf) - return false; + return {}; auto findCOFFSectionByName = [&](llvm::StringRef Name) -> std::pair, uint64_t> { @@ -481,7 +481,7 @@ class ReflectionContext ReflStrMdSec.first == nullptr && ConformMdSec.first == nullptr && MPEnumMdSec.first == nullptr) - return false; + return {}; ReflectionInfo Info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, @@ -502,7 +502,7 @@ class ReflectionContext auto Buf = this->getReader().readBytes(ImageStart, sizeof(llvm::object::dos_header)); if (!Buf) - return false; + return {}; auto DOSHdr = reinterpret_cast(Buf.get()); @@ -512,10 +512,10 @@ class ReflectionContext Buf = this->getReader().readBytes(RemoteAddress(PEHeaderAddress), sizeof(llvm::COFF::PEMagic)); if (!Buf) - return false; + return {}; if (memcmp(Buf.get(), llvm::COFF::PEMagic, sizeof(llvm::COFF::PEMagic))) - return false; + return {}; return readPECOFFSections(ImageStart, PotentialModuleNames); } @@ -550,7 +550,7 @@ class ReflectionContext const void *Buf = readData(0, sizeof(typename T::Header)); if (!Buf) - return false; + return {}; auto Hdr = reinterpret_cast(Buf); assert(Hdr->getFileClass() == T::ELFClass && "invalid ELF file class"); @@ -560,9 +560,9 @@ class ReflectionContext uint16_t SectionEntrySize = Hdr->e_shentsize; if (sizeof(typename T::Section) > SectionEntrySize) - return false; + return {}; if (SectionHdrNumEntries == 0) - return false; + return {}; // Collect all the section headers, we need them to look up the // reflection sections (by name) and the string table. @@ -573,7 +573,7 @@ class ReflectionContext uint64_t Offset = SectionHdrAddress + (I * SectionEntrySize); auto SecBuf = readData(Offset, sizeof(typename T::Section)); if (!SecBuf) - return false; + return {}; const typename T::Section *SecHdr = reinterpret_cast(SecBuf); @@ -597,7 +597,7 @@ class ReflectionContext auto StrTabBuf = readData(StrTabOffset, StrTabSize); if (!StrTabBuf) - return false; + return {}; auto StrTab = reinterpret_cast(StrTabBuf); bool Error = false; @@ -691,20 +691,15 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), true); if (Error) - return false; + return {}; - std::optional result = false; + std::optional result = {}; // We succeed if at least one of the sections is present in the // ELF executable. - if (FieldMdSec.first != nullptr || - AssocTySec.first != nullptr || - BuiltinTySec.first != nullptr || - CaptureSec.first != nullptr || - TypeRefMdSec.first != nullptr || - ReflStrMdSec.first != nullptr || - ConformMdSec.first != nullptr || - MPEnumMdSec.first != nullptr) { + if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first || + CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first || + ConformMdSec.first || MPEnumMdSec.first) { ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, @@ -739,16 +734,11 @@ class ReflectionContext ObjectFileFormat.getSectionName(ReflectionSectionKind::mpenum), false); if (Error) - return false; + return {}; - if (FieldMdSec.first != nullptr || - AssocTySec.first != nullptr || - BuiltinTySec.first != nullptr || - CaptureSec.first != nullptr || - TypeRefMdSec.first != nullptr || - ReflStrMdSec.first != nullptr || - ConformMdSec.first != nullptr || - MPEnumMdSec.first != nullptr) { + if (FieldMdSec.first || AssocTySec.first || BuiltinTySec.first || + CaptureSec.first || TypeRefMdSec.first || ReflStrMdSec.first || + ConformMdSec.first || MPEnumMdSec.first) { ReflectionInfo info = {{FieldMdSec.first, FieldMdSec.second}, {AssocTySec.first, AssocTySec.second}, {BuiltinTySec.first, BuiltinTySec.second}, @@ -819,7 +809,7 @@ class ReflectionContext // Read the first few bytes to look for a magic header. auto Magic = this->getReader().readBytes(ImageStart, sizeof(uint32_t)); if (!Magic) - return false; + return {}; uint32_t MagicWord; memcpy(&MagicWord, Magic.get(), sizeof(MagicWord)); From a014bd2cc8e03dbaf4fab3ccff331541abe3cb21 Mon Sep 17 00:00:00 2001 From: Alastair Houghton Date: Mon, 22 Apr 2024 11:14:27 +0100 Subject: [PATCH 15/15] [Build] Detect ld.gold version and prefer lld if gold is too old. If we're on a system that has ld.gold 2.35 or earlier, we want to use lld instead because otherwise we end up with duplicate sections in the output. rdar://123504095 --- CMakeLists.txt | 14 +++++++++++++- cmake/modules/GoldVersion.cmake | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/GoldVersion.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c76d78620d40b..d4690e3824b1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -983,6 +983,8 @@ endif() # Which default linker to use. Prefer LLVM_USE_LINKER if it set, otherwise use # our own defaults. This should only be possible in a unified (not stand alone) # build environment. +include(GoldVersion) + if(LLVM_USE_LINKER) set(SWIFT_USE_LINKER_default "${LLVM_USE_LINKER}") elseif(SWIFT_HOST_VARIANT_SDK STREQUAL "ANDROID") @@ -994,7 +996,17 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") elseif(DISTRO_NAME STREQUAL "Amazon Linux 2023") set(SWIFT_USE_LINKER_default "lld") else() - set(SWIFT_USE_LINKER_default "gold") + get_gold_version(gold_version) + if(NOT gold_version) + message(STATUS "GNU Gold not found; using lld instead") + set(SWIFT_USE_LINKER_default "lld") + elseif(gold_version VERSION_LESS "2.36") + message(STATUS "GNU Gold is too old (${gold_version}); using lld instead") + set(SWIFT_USE_LINKER_default "lld") + else() + message(STATUS "Using GNU Gold ${gold_version}") + set(SWIFT_USE_LINKER_default "gold") + endif() endif() set(SWIFT_USE_LINKER ${SWIFT_USE_LINKER_default} CACHE STRING "Build Swift with a non-default linker") diff --git a/cmake/modules/GoldVersion.cmake b/cmake/modules/GoldVersion.cmake new file mode 100644 index 0000000000000..b99f586c47424 --- /dev/null +++ b/cmake/modules/GoldVersion.cmake @@ -0,0 +1,18 @@ +# Find the version of ld.gold, if installed. +# +# Versions prior to 2.36 break Swift programs because they won't coalesce +# sections with different SHF_GNU_RETAIN flags. +function(get_gold_version result_var_name) + find_program(gold_executable "ld.gold") + if(gold_executable) + execute_process( + COMMAND "${gold_executable}" "--version" + COMMAND "head" "-n" "1" + COMMAND "sed" "-e" "s/^.* (\\([^)]*\\)).*$/\\1/g;s/.* \\([0-9][0-9]*\\(\\.[0-9][0-9]*\\)*\\).*/\\1/g" + OUTPUT_VARIABLE gold_version + OUTPUT_STRIP_TRAILING_WHITESPACE) + set("${result_var_name}" "${gold_version}" PARENT_SCOPE) + else() + set("${result_var_name}" "" PARENT_SCOPE) + endif() +endfunction()