Skip to content

Commit 8feba8d

Browse files
authored
Use __ehdr_start on ELF instead of calling dladdr(). (#85012)
This PR replaces our use of `__dso_handle` and (indirectly) `dladdr()` when figuring out the base address of loaded Swift images on ELF-based platforms. Instead, we use `__ehdr_start` which refers to the start of the image's ELF header (i.e. the start of the file) and is provided by the compiler/linker for this purpose. This pointer is consumed by `swift_addNewDSOImage()` and, later, by Swift Testing when running tests, but is otherwise unused, so the less work we do on it at runtime, the better. A fallback path is present that, for images that do not contain `__ehdr_start`, derives the address by calling `dladdr()` on the section structure's address. Resolves #84997.
1 parent b8cbb22 commit 8feba8d

File tree

4 files changed

+29
-86
lines changed

4 files changed

+29
-86
lines changed

stdlib/public/SwiftShims/swift/shims/MetadataSections.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,15 @@ struct MetadataSections {
5858
/// symbol in the image that contains these sections.
5959
///
6060
/// For Mach-O images, set this field to \c __dso_handle (i.e. the Mach header
61-
/// for the image.) For ELF images, set it to \c __dso_handle (the runtime
62-
/// will adjust it to the start of the ELF image when the image is loaded.)
63-
/// For COFF images, set this field to \c __ImageBase.
61+
/// for the image.) For ELF images, set it to \c __ehdr_start. For COFF
62+
/// images, set this field to \c __ImageBase.
6463
///
6564
/// For platforms that have a single statically-linked image or no dynamic
66-
/// loader (i.e. no equivalent of \c __dso_handle or \c __ImageBase), this
67-
/// field is ignored and should be set to \c nullptr.
68-
///
69-
/// \bug When imported into Swift, this field is not atomic.
65+
/// loader (i.e. no equivalent of \c __dso_handle, \c __ehdr_start, or
66+
/// \c __ImageBase), this field is ignored and should be set to \c nullptr.
7067
///
7168
/// \sa swift_addNewDSOImage()
72-
#if defined(__swift__) || defined(__STDC_NO_ATOMICS__)
7369
const void *baseAddress;
74-
#elif defined(__cplusplus)
75-
std::atomic<const void *> baseAddress;
76-
#else
77-
_Atomic(const void *) baseAddress;
78-
#endif
7970

8071
/// Unused.
8172
///

stdlib/public/runtime/ImageInspectionCommon.cpp

Lines changed: 12 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -28,67 +28,25 @@
2828
#include "swift/Runtime/Concurrent.h"
2929

3030
#include <algorithm>
31-
#include <atomic>
3231
#include <cstdlib>
3332

3433
namespace swift {
35-
36-
static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;
37-
38-
/// Adjust the \c baseAddress field of a metadata sections structure.
39-
///
40-
/// \param sections A pointer to a valid \c swift::MetadataSections structure.
41-
///
42-
/// This function should be called at least once before the structure or its
43-
/// address is passed to code outside this file to ensure that the structure's
44-
/// \c baseAddress field correctly points to the base address of the image it
45-
/// is describing.
46-
static void fixupMetadataSectionBaseAddress(swift::MetadataSections *sections) {
47-
bool fixupNeeded = false;
48-
49-
#if defined(__ELF__)
50-
// If the base address was set but the image is an ELF image, it is going to
51-
// be __dso_handle which is not the value we expect (Dl_info::dli_fbase), so
52-
// we need to fix it up.
53-
fixupNeeded = true;
54-
#elif !defined(__MACH__)
55-
// For non-ELF, non-Apple platforms, if the base address is nullptr, it
56-
// implies that this image was built against an older version of the runtime
57-
// that did not capture any value for the base address.
58-
auto oldBaseAddress = sections->baseAddress.load(std::memory_order_relaxed);
59-
if (!oldBaseAddress) {
60-
fixupNeeded = true;
61-
}
62-
#endif
63-
64-
if (fixupNeeded) {
65-
// We need to fix up the base address. We'll need a known-good address in
66-
// the same image: `sections` itself will work nicely.
67-
auto symbolInfo = SymbolInfo::lookup(sections);
68-
if (symbolInfo.has_value() && symbolInfo->getBaseAddress()) {
69-
sections->baseAddress.store(symbolInfo->getBaseAddress(),
70-
std::memory_order_relaxed);
71-
}
72-
}
73-
}
34+
static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;
7435
}
7536

7637
SWIFT_RUNTIME_EXPORT
7738
void swift_addNewDSOImage(swift::MetadataSections *sections) {
78-
#if 0
79-
// Ensure the base address of the sections structure is correct.
80-
//
81-
// Currently disabled because none of the registration functions below
82-
// actually do anything with the baseAddress field. Instead,
83-
// swift_enumerateAllMetadataSections() is called by other individual
84-
// functions, lower in this file, that yield metadata section pointers.
85-
//
86-
// If one of these registration functions starts needing the baseAddress
87-
// field, this call should be enabled and the calls elsewhere in the file can
88-
// be removed.
89-
swift::fixupMetadataSectionBaseAddress(sections);
39+
#if defined(__ELF__)
40+
if (!sections->baseAddress || sections->version <= 4) {
41+
// The base address was either unavailable at link time or is set to the
42+
// wrong value and will need to be recomputed. We can use the address of the
43+
// sections structure and derive the base address from there.
44+
if (auto info = swift::SymbolInfo::lookup(sections)) {
45+
sections->baseAddress = info->getBaseAddress();
46+
}
47+
}
9048
#endif
91-
auto baseAddress = sections->baseAddress.load(std::memory_order_relaxed);
49+
auto baseAddress = sections->baseAddress;
9250

9351
const auto &protocols_section = sections->swift5_protocols;
9452
const void *protocols = reinterpret_cast<void *>(protocols_section.start);
@@ -144,9 +102,6 @@ void swift_enumerateAllMetadataSections(
144102
) {
145103
auto snapshot = swift::registered->snapshot();
146104
for (swift::MetadataSections *sections : snapshot) {
147-
// Ensure the base address is fixed up before yielding the pointer.
148-
swift::fixupMetadataSectionBaseAddress(sections);
149-
150105
// Yield the pointer and (if the callback returns false) break the loop.
151106
if (!(* body)(sections, context)) {
152107
return;
@@ -180,11 +135,6 @@ const swift::MetadataSections *swift_getMetadataSection(size_t index) {
180135
result = snapshot[index];
181136
}
182137

183-
if (result) {
184-
// Ensure the base address is fixed up before returning it.
185-
swift::fixupMetadataSectionBaseAddress(result);
186-
}
187-
188138
return result;
189139
}
190140

@@ -208,11 +158,7 @@ void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
208158
} else {
209159
*out_actual = nullptr;
210160
}
211-
212-
// fixupMetadataSectionBaseAddress() was already called by
213-
// swift_getMetadataSection(), presumably on the same thread, so we don't need
214-
// to call it again here.
215-
*out_expected = section->baseAddress.load(std::memory_order_relaxed);
161+
*out_expected = section->baseAddress;
216162
}
217163

218164
SWIFT_RUNTIME_EXPORT

stdlib/public/runtime/ImageInspectionCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
namespace swift {
5353
struct MetadataSections;
54-
static constexpr const uintptr_t CurrentSectionMetadataVersion = 4;
54+
static constexpr const uintptr_t CurrentSectionMetadataVersion = 5;
5555
}
5656

5757
struct SectionInfo {

stdlib/public/runtime/SwiftRT-ELF-WASM.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,7 @@
1919
#include <new>
2020

2121
#if defined(__ELF__)
22-
extern "C" const char __dso_handle[];
23-
#elif defined(__wasm__)
24-
// NOTE: Multi images in a single process is not yet
25-
// stabilized in WebAssembly toolchain outside of Emscripten.
26-
static constexpr const void *__dso_handle = nullptr;
22+
extern "C" const char __ehdr_start[] __attribute__((__weak__));
2723
#endif
2824

2925
#if SWIFT_ENABLE_BACKTRACING
@@ -92,9 +88,19 @@ static void swift_image_constructor() {
9288
{ reinterpret_cast<uintptr_t>(&__start_##name), \
9389
static_cast<uintptr_t>(&__stop_##name - &__start_##name) }
9490

91+
const void *baseAddress = nullptr;
92+
#if defined(__ELF__)
93+
if (&__ehdr_start != nullptr) {
94+
baseAddress = __ehdr_start;
95+
}
96+
#elif defined(__wasm__)
97+
// NOTE: Multi images in a single process is not yet stabilized in WebAssembly
98+
// toolchain outside of Emscripten.
99+
#endif
100+
95101
::new (&sections) swift::MetadataSections {
96102
swift::CurrentSectionMetadataVersion,
97-
{ __dso_handle },
103+
baseAddress,
98104

99105
nullptr,
100106
nullptr,

0 commit comments

Comments
 (0)