Skip to content

Conversation

al45tair
Copy link
Contributor

@al45tair al45tair commented Mar 4, 2024

We want to support section GC, and the __start and __stop symbols don't count as roots for that (at least, not by default). Additionally, while GNU ld and lld will coalesce retained and non-retained sections, gold refuses to do so (see https://sourceware.org/bugzilla/show_bug.cgi?id=31415), which trips up the reflection code because that only expects to find a single section.

Turn on the SHF_GNU_RETAIN flag in swiftrt.o, and remove the existing workarounds for both of the above.

Also fix generation of module objects to be section GC compatible by marking the __Swift_AST symbol as used and finalising the module in IRGen.

Additionally, it turns out that we weren't initialising the llvm::TargetOptions properly and in particular the UseInitArray setting was wrong; this is masked by code in gold that converts .ctors and .dtors sections into .init_array and .fini_array respectively, but lld does not do this, and since Glibc no longer calls functions in these sections, that means that when linked with lld, any constructors or destructors generated by the Swift compiler don't run. Fix by setting UseInitArray.

rdar://123504095

@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

@swift-ci Please test

@finagolfin
Copy link
Member

Glad that you're trying to fix this properly, this closes #60406? Any plans to get this into 5.10 or will that have to rely on my old workaround of extra lld flags instead?

@kateinoigakukun
Copy link
Member

@swift-ci test WebAssembly

@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

Glad that you're trying to fix this properly, this closes #60406?

Looks like it will, yes.

@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

$ SWIFT_DRIVER_TEST_OPTIONS=" -Xlinker --gc-sections -use-ld=gold" utils/run-test --build-dir ../build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64 ... Testing Time: 1005.77s Unsupported : 2075 Passed : 8500 Expectedly Failed: 33 2 warning(s) in tests 
@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

$ SWIFT_DRIVER_TEST_OPTIONS=" -Xlinker --gc-sections -use-ld=lld" utils/run-test --build-dir ../build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64 ... Testing Time: 1005.83s Unsupported : 2075 Passed : 8500 Expectedly Failed: 33 2 warning(s) in tests 
@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

Hmmmm… not sure what this is all about:

Failed Tests (5): Swift(linux-x86_64) :: SourceKit/Compile/basic.swift Swift(linux-x86_64) :: SourceKit/CursorInfo/cursor_swiftinterface.swift Swift(linux-x86_64) :: SourceKit/DocSupport/doc_system_module_underscored.swift Swift(linux-x86_64) :: SourceKit/InterfaceGen/gen_swift_module.swift Swift(linux-x86_64) :: SourceKit/Macros/macro_option_set.swift 

Will take a look at that tomorrow.

@al45tair
Copy link
Contributor Author

al45tair commented Mar 4, 2024

Any plans to get this into 5.10 or will that have to rely on my old workaround of extra lld flags instead?

It won't be in 5.10.0. I think it'd be worth getting it into a point release though.

Copy link
Member

@etcwilde etcwilde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like the right direction. I would like a bit more in-source documentation about what it's doing and why we need the two sets of sections, what it means for a symbol to be in one but not the other, etc...

@al45tair
Copy link
Contributor Author

al45tair commented Mar 5, 2024

The SourceKit test failures are all of the form

Optimizer/Verifier.swift:22: Fatal error: instruction <some instruction> should conform to ForwardingInstruction 

which seems to relate to something @eeckstein added on the 14th of February. They don't seem to be related to the changes in this PR.

@al45tair
Copy link
Contributor Author

al45tair commented Mar 5, 2024

@swift-ci Please test

@al45tair
Copy link
Contributor Author

al45tair commented Mar 5, 2024

@swift-ci test WebAssembly

Copy link
Member

@etcwilde etcwilde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks for the docs. There's so little actual documentation on a lot of the linkage behaviors that I think it's important to have it written down somewhere.

@al45tair
Copy link
Contributor Author

al45tair commented Mar 5, 2024

OK. Apparently the problem with the SourceKit tests is that the sourcekitd-test executable doesn't link swiftrt.o. That should be easy enough to fix.

al45tair and others added 13 commits April 29, 2024 10:48
…tions. 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
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
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
`gold` and `lld` produce map files in different formats; this test can and should work for both of them. rdar://123504095
When testing different linkers, it's sometimes useful to run the tests with `SWIFT_DRIVER_TEST_OPTIONS=" -use-ld=<linker>"`. 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
 Since this is adjacent to a `!=` operator, explicitly using `bool` seems clearer. Co-authored-by: Evan Wilde <etceterawilde@gmail.com>
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
Add a comment to ReflectionContext.h explaining the situation regarding `SHF_GNU_RETAIN` and the reflection metadata sections. rdar://123504095
Without `retain` here, we might remove the reference that pulls in the backtracing support code. rdar://123504095
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
This doesn't change any code, just makes things look slightly neater. rdar://123504095
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
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
@al45tair
Copy link
Contributor Author

(For those following this PR, I'm still working on the LLDB issues. One of them is fixed here: llvm/llvm-project#90099, but there are some more things going wrong for some reason.)

@al45tair
Copy link
Contributor Author

al45tair commented Apr 30, 2024

OK, so the "more things going wrong" are actually the same problem as the one fixed in llvm/llvm-project#90099. a014bd2 only works around it for libswiftCore.so (and other things built by the Swift build system), but it doesn't work around it for LLDB's tests.

What was happening there, FWIW, was that a number of tests set a breakpoint on main, which, if there are two .text sections and LLDB doesn't have the fix from llvm/llvm-project#90099, typically results in a breakpoint on main (as expected) but also one on __start (because that symbol is at the beginning of the other .text section). Then when you run the program, it stops at __start instead of stopping in main, and since __start isn't a Swift frame, the language defaults to C, so evaluating Swift expressions doesn't work (they don't parse as C), and it's also not the expected frame, so the variables the tests expect to be able to inspect aren't there.

@al45tair
Copy link
Contributor Author

al45tair commented May 1, 2024

// 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
Copy link
Contributor

@drodriguez drodriguez May 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change takes the stdout and stderr of %target-build-stdlib pass each line through sed that replaces lines that say either gold or LLD with just those word, and convert everything to upper case. Then the result of all that is passed as --check-prefix?

What happens when -v prints more than one line? All the lines will be printed and passed to as extra arguments to %FileCheck?

$ echo -e 'foo\nbar\nthis will say LLD\nbaz' | sed 's/.*\(gold\|LLD\).*/\1/g' foo bar LLD baz 

Am I missing something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#73470 73470

al45tair pushed a commit to al45tair/swift that referenced this pull request May 7, 2024
In swiftlang#72061 the test was modified because LLD and Gold linker map formats are different, so they need different CHECKs. The original method in PR swiftlang#72061 presents problems when the output is not exactly only one line. These changes use the first line of the linker map file to decide if the Gold or the LLD linker map checks should be used, since the format differs in both for the first line. This way of checking works in my Linux machine when using the default linker, when forcing Gold with `-use-ld=gold` and when forcing LLD with `-use-ld=lld`.
al45tair pushed a commit that referenced this pull request May 7, 2024
In #72061 the test was modified because LLD and Gold linker map formats are different, so they need different CHECKs. The original method in PR #72061 presents problems when the output is not exactly only one line. These changes use the first line of the linker map file to decide if the Gold or the LLD linker map checks should be used, since the format differs in both for the first line. This way of checking works in my Linux machine when using the default linker, when forcing Gold with `-use-ld=gold` and when forcing LLD with `-use-ld=lld`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

7 participants