-
Notifications
You must be signed in to change notification settings - Fork 10.5k
ELF registration Restructuring #12758
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
Conversation
CC: @dcci @modocache @hpux735 @jrose-apple not sure if you remember anyone else who may be interested in this reworking |
perhaps @tienex ? |
After a quick glance, I think this is great. To be perfectly honest, it's a little over my head (this was Tienex's innovation). To perform robust regression testing on arm, however, we have work to do to get Swift 4+ working there. |
ea3f8e6
to
ea16d85
Compare
I'd want a @jckarter or @gparker42 to comment on it as well. |
lib/Driver/ToolChains.cpp
Outdated
SmallString<128> srtPath = SharedRuntimeLibPath; | ||
llvm::sys::path::append(srtPath, | ||
swift::getMajorArchitectureName(getTriple())); | ||
llvm::sys::path::append(srtPath, "srt.o"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a more descriptive name we can use than srt
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"swiftrt.o" would be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even just "swiftRuntime.o", we don't have to pay for bandwidth by the bit anymore!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not tied to the name. swiftrt.o
sounds good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an outsider I wouldn't have immediately guessed that srt/swiftrt concerns the runtime (even if it seems obvious in hindsight). There is value in spelling things out and the cost is low.
@@ -2335,7 +2335,7 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { | |||
sectionName = "__TEXT, __swift2_proto, regular, no_dead_strip"; | |||
break; | |||
case llvm::Triple::ELF: | |||
sectionName = ".swift2_protocol_conformances"; | |||
sectionName = "swift2_protocol_conformances"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we keep the existing symbol names to avoid unnecessary ABI thrash? I don't know what other tools might be looking for these symbol names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that is part of the magic. The reason for changing the section names here is to permit the linker to generate the start and stop markers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the reflection metadata symbols still be found out-of-process by the remote reflection library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that is what Im seeing now. The protocol conformances and the type metadata works, but the reflection metadata is causing some problems. The section exists and it can find the section (as it is not coalesced into .data
). The problem is that there is a section load offset that needs to be accounted for (as otherwise the relative pointer is now pointing to the wrong location) or swift-reflection-dump
for example gets things wrong.
|
||
swift_addNewDSOImage(§ions); | ||
|
||
#undef SWIFT_SECTION_RANGE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is doing quite a bit more work and hardcoding more ABI liability into the static constructor than before. The static constructor should ideally do nothing more than make a runtime call, so that the runtime can be upgraded with additional capabilities without recompiling dynamic libraries. Since the static constructor runs eagerly at load time for libraries the executable links against, it's also important that it do as little work as possible if no lazily-instantiated runtime mechanisms have been initialized that require runtime instantiation. I think the previous approach of having the runtime inspect the image is preferable for these reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree. The new static constructor is doing negligible work: it merely collects a small number of image-local addresses and calls the runtime function. This arrangement avoids the vastly more expensive cost of calling dlsym()
to find the sections later.
The version field in the MetadataSections
provides sufficient ABI flexibility. New fields can be added to it; new runtimes can recognize calls from old libraries that don't have those fields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH, this design means that future runtimes only have access to the information we have the forethought to feed them through this MetadataSections
record, instead of potentially any information we can glean from the image. (One could argue the difference is marginal in practice, since we'd still need to consciously export a symbol to reliably discover anything dynamically in the old model anyway.)
It seems to me like we still shouldn't have to do any work in the static constructor here, since the data structure here is nothing but a bunch of local references. We should be able to make the MetadataSections
record here a global constant, full of relative references, so the only load-time work the constructor has to do is call the runtime with a pointer to the global constant. Using a global constant could still give us the flexibility to dladdr
the pointer and get back to a general dso handle we can do deeper inspection on if we wanted to in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jckarter I'd love to make that a global constant. I just could not figure out how to make that a global constant (at least within C). I suppose that a C++ constructor could be emitted to construct the global structure.
IMO, this is doing a very small amount of work, which would ideally be just the runtime registration call, but I could not make the structure a global constant. That would be my preference as well. But, yes, the should is exactly what I think is ideal: the structure is a constant global, the constructor is just to tie to into the runtime.
Also note that this vastly simplifies the linker support needed. It obviates the need to place objects at a particular location as well as the special symbol construction and placement. This now relies solely on the standard required behavior for inspecting the linker tables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, neither C's nor C++'s model for constant expressions is expressive enough here. You might be able to express it as LLVM IR, though, or as global inline assembly. Since it's just data it should be portable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling dladdr()
on any of the values passed in MetadataSections
ought to recover the dso handle. We could add a field to MetadataSections
that is simply a non-nil pointer somewhere into the image, to ensure that dladdr()
has a target even if the image happens to have none of the other data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gparker42 that is one of the tricks that I'm playing here. The reason for the global inline assembly, as gross as it may be, is that it forces that the section will be constructed, which will force the emission of the start/stop symbols. These are referenced by the table thus preventing the dead strip from kicking in. As a result, we are guaranteed that the markers will always be present, though the section may be 0-sized. The symbols are image specific, so we are guaranteed to have a local symbol to reference to get the DSO handle.
ea16d85
to
fd82c92
Compare
CC: @zbowling this is the change that I was referring to (there is something odd going on with the actual reading of the registration data that I need to figure out, and then this is ready to go I think) |
Awesome, yeah, this should work on Fuchsia. |
@zbowling yeah, and should be faster/smaller as well (this is ELF specific rather than OS specific now) |
@jckarter @rjmccall @gparker42 any suggestions as to where to start digging to figure out why strings are being printed as:
Adding some tracing shows that the metadata is being identified and tabled correctly. |
That probably indicates that the protocol conformances aren't getting indexed properly, so the lookup for String's CustomStringConvertible conformance is failing. |
Ugh, I had forgot to populate two of the functions sigh. This should be relatively easy to fix and finish up. |
f5d4bb8
to
594e609
Compare
@swift-ci please test linux platform |
Build failed |
594e609
to
415f552
Compare
@swift-ci please test linux platform |
Build failed |
The Swift/Arm team (specifically @uraimo ) tested this patch, and it improved Swift 4+ on arm. This patch seems to have fixed regressions in the REPL that have come up since Swift 3.1.1. |
SWIFT_SECTION_RANGE(swift3_reflstr), | ||
SWIFT_SECTION_RANGE(swift3_fieldmd), | ||
SWIFT_SECTION_RANGE(swift3_assocty), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Clang manage to compile this into a global constant, despite not formally being constexpr by C++ rules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No :-(. I think that I would rather do that as a follow up. We can try out a few different things to see if we can do something more clever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM.
initializeSectionLookup(&ProtocolConformanceArgs); | ||
const char *conformances = &__start_swift2_protocol_conformances; | ||
if (size_t length = &__stop_swift2_protocol_conformances - conformances) | ||
addImageProtocolConformanceBlockCallback(conformances, length); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the standard library conformances have already been registered by libswiftCore.so's own static constructor by this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, thats what I expected, but interestingly enough, that was the tweak that fixed everything (minus a copy-pasta error).
5f319c5
to
2ab930b
Compare
Please test with following pull request: @swift-ci please test |
Build failed |
Build failed |
Restructure the ELF handling to be completely agnostic to the OS. Rather than usng the loader to query the section information, use the linker to construct linker tables and synthetic markers for the beginning and of the table. Save off the values of these pointers and pass them along through the constructor to the runtime for registration. This removes the need for the begin/end objects. Remove the special construction of the begin/end objects through the special assembly constructs, preferring to do this in C with a bit of inline assembly to ensure that the section is always allocated. Remove the special handling for the various targets, the empty object file can be linked on all the targets. The new object file has no requirements on the ordering. It needs to simply be injected into the link. Name the replacement file `swiftrt.o` mirroring `crt.o` from libc. Merge the constructor and the definition into a single object file. This approach is generally more portable, overall simpler to implement, and more robust. Thanks to Orlando Bassotto for help analyzing some of the odd behaviours when switching over.
2ab930b
to
098b44f
Compare
Please test with following pull request: @swift-ci please test Linux platform |
Build failed |
@swift-ci please test macOS platform |
Build failed |
Please test with following pull request: @swift-ci please test Linux platform |
Build failed |
Please test with following pull request: @swift-ci please test Linux platform |
Build failed |
Please test with following pull request: @swift-ci please test macOS platform |
Build failed |
ELF is segment mapped, where the segment which contains a particular section may be mapped to an address which does not correspond to the address on disk. Since the reflection dumper does not use the loader to load the image into memory, we must manually account for any section offsets. Calculate this value when we query the mmap'ed image and wire it through to the relative direct pointer accesses. When switching to the linker table approach for the ELF metadata introspection, this was uncovered as the segment containing the orphaned sections was coalesced into a separate PT_LOAD header which had a non-0 offset for the mapping.
This test fails with LSAN. It is unclear why this is failing with the ELF metadata change. This looks like a latent issue. XFAIL it until we can properly look into this.
098b44f
to
28dffe7
Compare
@swift-ci please test |
Build failed |
Build failed |
Please test with following pull request: @swift-ci please smoke test Linux platform |
Please test with following pull request: @swift-ci please test |
Apparently. For the record, #13180 addressed that failure that the testing didnt catch. |
Restructure the ELF handling to be completely agnostic to the OS.
Rather than usng the loader to query the section information, use the
linker to construct linker tables and synthetic markers for the
beginning and of the table. Save off the values of these pointers and
pass them along through the constructor to the runtime for registration.
This removes the need for the begin/end objects. Remove the special
construction of the begin/end objects through the special assembly
constructs, preferring to do this in C with a bit of inline assembly to
ensure that the section is always allocated.
Remove the special handling for the various targets, the empty object
file can be linked on all the targets.
The new object file has no requirements on the ordering. It needs to
simply be injected into the link.
Name the replacement file
srt.o
mirroringcrt.o
from libc. Mergethe constructor and the definition into a single object file.
This approach is generally more portable, overall simpler to implement,
and more robust.
Replace this paragraph with a description of your changes and rationale. Provide links to external references/discussions if appropriate.
Resolves SR-NNNN.