Skip to content

[Linux][Runtime][IRGen] Mark metadata sections as retained and support section GC. #72061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 4, 2024

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
Contributor

@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
Contributor

@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

swiftlang/llvm-project#8661

@swift-ci Please test

@al45tair al45tair merged commit 6afdcd3 into swiftlang:main May 4, 2024
5 checks passed
finagolfin added a commit to finagolfin/swift that referenced this pull request May 6, 2024
finagolfin added a commit to finagolfin/swift-driver that referenced this pull request May 6, 2024
…g -z nostart-stop-gc"

This reverts c771555, now that it was properly fixed in swiftlang/swift#72061.
@@ -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
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants