Skip to content

Commit 099fdc2

Browse files
committed
Fix an issue on COFF/ELF targets where the runtime would register each loaded image twice (at least early on.)
1 parent d1bb98b commit 099fdc2

12 files changed

+222
-101
lines changed

stdlib/public/SwiftShims/MetadataSections.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,25 @@ typedef struct MetadataSectionRange {
3939
/// Identifies the address space ranges for the Swift metadata required by the Swift runtime.
4040
struct MetadataSections {
4141
__swift_uintptr_t version;
42-
__swift_uintptr_t reserved;
42+
43+
/// The base address of the image where this metadata section was defined, as
44+
/// reported when the section was registered with the Swift runtime.
45+
///
46+
/// The value of this field is equivalent to the value of
47+
/// \c SymbolInfo::baseAddress as returned from \c lookupSymbol() for a symbol
48+
/// in the image that contains these sections.
49+
///
50+
/// For Mach-O images, set this field to \c __dso_handle (i.e. the Mach header
51+
/// for the image.) For ELF images, set it to \c __dso_handle (the runtime
52+
/// will adjust it to the start of the ELF image when the image is loaded.)
53+
/// For COFF images, set this field to \c __ImageBase.
54+
///
55+
/// For platforms that have a single statically-linked image or no dynamic
56+
/// loader (i.e. no equivalent of \c __dso_handle or \c __ImageBase), this
57+
/// field is ignored and should be set to \c nullptr.
58+
///
59+
/// \sa swift_addNewDSOImage()
60+
const void *baseAddress;
4361

4462
/// `next` and `prev` are used by the runtime to construct a
4563
/// circularly doubly linked list to quickly iterate over the metadata

stdlib/public/runtime/AccessibleFunction.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ static void _registerAccessibleFunctions(AccessibleFunctionsState &C,
9898
C.SectionsToScan.push_back(section);
9999
}
100100

101-
void swift::addImageAccessibleFunctionsBlockCallbackUnsafe(const void *functions,
102-
uintptr_t size) {
101+
void swift::addImageAccessibleFunctionsBlockCallbackUnsafe(
102+
const void *baseAddress, const void *functions, uintptr_t size) {
103103
assert(
104104
size % sizeof(AccessibleFunctionRecord) == 0 &&
105105
"accessible function section not a multiple of AccessibleFunctionRecord");
@@ -108,10 +108,10 @@ void swift::addImageAccessibleFunctionsBlockCallbackUnsafe(const void *functions
108108
_registerAccessibleFunctions(C, AccessibleFunctionsSection{functions, size});
109109
}
110110

111-
void swift::addImageAccessibleFunctionsBlockCallback(const void *functions,
112-
uintptr_t size) {
111+
void swift::addImageAccessibleFunctionsBlockCallback(
112+
const void *baseAddress, const void *functions, uintptr_t size) {
113113
Functions.get();
114-
addImageAccessibleFunctionsBlockCallbackUnsafe(functions, size);
114+
addImageAccessibleFunctionsBlockCallbackUnsafe(baseAddress, functions, size);
115115
}
116116

117117
static const AccessibleFunctionRecord *

stdlib/public/runtime/ImageInspection.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,31 @@ void initializeDynamicReplacementLookup();
7777
void initializeAccessibleFunctionsLookup();
7878

7979
// Callbacks to register metadata from an image to the runtime.
80-
void addImageProtocolsBlockCallback(const void *start, uintptr_t size);
81-
void addImageProtocolsBlockCallbackUnsafe(const void *start, uintptr_t size);
82-
void addImageProtocolConformanceBlockCallback(const void *start,
80+
void addImageProtocolsBlockCallback(const void *baseAddress,
81+
const void *start, uintptr_t size);
82+
void addImageProtocolsBlockCallbackUnsafe(const void *baseAddress,
83+
const void *start, uintptr_t size);
84+
void addImageProtocolConformanceBlockCallback(const void *baseAddress,
85+
const void *start,
8386
uintptr_t size);
84-
void addImageProtocolConformanceBlockCallbackUnsafe(const void *start,
87+
void addImageProtocolConformanceBlockCallbackUnsafe(const void *baseAddress,
88+
const void *start,
8589
uintptr_t size);
86-
void addImageTypeMetadataRecordBlockCallback(const void *start,
90+
void addImageTypeMetadataRecordBlockCallback(const void *baseAddress,
91+
const void *start,
8792
uintptr_t size);
88-
void addImageTypeMetadataRecordBlockCallbackUnsafe(const void *start,
93+
void addImageTypeMetadataRecordBlockCallbackUnsafe(const void *baseAddress,
94+
const void *start,
8995
uintptr_t size);
90-
void addImageDynamicReplacementBlockCallback(const void *start, uintptr_t size,
96+
void addImageDynamicReplacementBlockCallback(const void *baseAddress,
97+
const void *start, uintptr_t size,
9198
const void *start2,
9299
uintptr_t size2);
93-
void addImageAccessibleFunctionsBlockCallback(const void *start,
100+
void addImageAccessibleFunctionsBlockCallback(const void *baseAddress,
101+
const void *start,
94102
uintptr_t size);
95-
void addImageAccessibleFunctionsBlockCallbackUnsafe(const void *start,
103+
void addImageAccessibleFunctionsBlockCallbackUnsafe(const void *baseAddress,
104+
const void *start,
96105
uintptr_t size);
97106

98107
int lookupSymbol(const void *address, SymbolInfo *info);

stdlib/public/runtime/ImageInspectionCommon.cpp

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828

2929
namespace swift {
3030

31+
#ifndef NDEBUG
3132
static swift::MetadataSections *registered = nullptr;
3233

33-
void record(swift::MetadataSections *sections) {
34+
static void record(swift::MetadataSections *sections) {
3435
if (registered == nullptr) {
3536
registered = sections;
3637
sections->next = sections->prev = sections;
@@ -41,34 +42,70 @@ void record(swift::MetadataSections *sections) {
4142
registered->prev = sections;
4243
}
4344
}
45+
#endif
46+
47+
static const void *
48+
getMetadataSectionBaseAddress(swift::MetadataSections *sections) {
49+
// If the base address was not set by the caller of swift_addNewDSOImage()
50+
// then we can assume that the caller was built against an older version of
51+
// the runtime that did not capture a value for this field. Currently nothing
52+
// is actively using the image's base address outside of tests that are built
53+
// with the runtime/stdlib, so there's no need to try to fix up the value. If
54+
// something in the runtime starts using it, we will want to either:
55+
// 1. Resolve the address from a known-good address like swift5_protocols when
56+
// the image is first loaded (in this function);
57+
// 1. Resolve the address from a known-good address like swift5_protocols when
58+
// the address is first used (and atomically swap the address back so we
59+
// don't incur the cost of lookupSymbol() each time we need it; or
60+
// 3. Introduce an ABI-breaking change so that all binaries are rebuilt and
61+
// start supplying a value for this field.
62+
63+
#ifndef NDEBUG
64+
#if defined(__ELF__)
65+
// If the base address was set but the image is an ELF image, it is going to
66+
// be __dso_handle which is not the value we expect (Dl_info::dli_fbase), so
67+
// we need to fix it up. Since the base address is currently unused by the
68+
// runtime outside tests, we don't normally do this work.
69+
if (auto baseAddress = sections->baseAddress) {
70+
swift::SymbolInfo symbolInfo;
71+
if (lookupSymbol(baseAddress, &symbolInfo) && symbolInfo.baseAddress) {
72+
sections->baseAddress = symbolInfo.baseAddress;
73+
}
74+
}
75+
#endif
76+
#endif
77+
78+
return sections->baseAddress;
79+
}
4480
}
4581

4682
SWIFT_RUNTIME_EXPORT
47-
void swift_addNewDSOImage(const void *addr) {
48-
// We cast off the const in order to update the linked list
49-
// data structure. This is safe to do since we don't touch
50-
// any other fields.
51-
swift::MetadataSections *sections =
52-
static_cast<swift::MetadataSections *>(const_cast<void *>(addr));
53-
83+
void swift_addNewDSOImage(swift::MetadataSections *sections) {
84+
#ifndef NDEBUG
5485
record(sections);
86+
#endif
87+
88+
auto baseAddress = swift::getMetadataSectionBaseAddress(sections);
5589

5690
const auto &protocols_section = sections->swift5_protocols;
5791
const void *protocols = reinterpret_cast<void *>(protocols_section.start);
5892
if (protocols_section.length)
59-
swift::addImageProtocolsBlockCallback(protocols, protocols_section.length);
93+
swift::addImageProtocolsBlockCallback(baseAddress,
94+
protocols, protocols_section.length);
6095

6196
const auto &protocol_conformances = sections->swift5_protocol_conformances;
6297
const void *conformances =
6398
reinterpret_cast<void *>(protocol_conformances.start);
6499
if (protocol_conformances.length)
65-
swift::addImageProtocolConformanceBlockCallback(conformances,
100+
swift::addImageProtocolConformanceBlockCallback(baseAddress, conformances,
66101
protocol_conformances.length);
67102

68103
const auto &type_metadata = sections->swift5_type_metadata;
69104
const void *metadata = reinterpret_cast<void *>(type_metadata.start);
70105
if (type_metadata.length)
71-
swift::addImageTypeMetadataRecordBlockCallback(metadata, type_metadata.length);
106+
swift::addImageTypeMetadataRecordBlockCallback(baseAddress,
107+
metadata,
108+
type_metadata.length);
72109

73110
const auto &dynamic_replacements = sections->swift5_replace;
74111
const auto *replacements =
@@ -77,7 +114,7 @@ void swift_addNewDSOImage(const void *addr) {
77114
const auto &dynamic_replacements_some = sections->swift5_replac2;
78115
const auto *replacements_some =
79116
reinterpret_cast<void *>(dynamic_replacements_some.start);
80-
swift::addImageDynamicReplacementBlockCallback(
117+
swift::addImageDynamicReplacementBlockCallback(baseAddress,
81118
replacements, dynamic_replacements.length, replacements_some,
82119
dynamic_replacements_some.length);
83120
}
@@ -87,70 +124,22 @@ void swift_addNewDSOImage(const void *addr) {
87124
reinterpret_cast<void *>(accessible_funcs_section.start);
88125
if (accessible_funcs_section.length)
89126
swift::addImageAccessibleFunctionsBlockCallback(
90-
functions, accessible_funcs_section.length);
127+
baseAddress, functions, accessible_funcs_section.length);
91128
}
92129

93130
void swift::initializeProtocolLookup() {
94-
const swift::MetadataSections *sections = registered;
95-
while (true) {
96-
const swift::MetadataSectionRange &protocols =
97-
sections->swift5_protocols;
98-
if (protocols.length)
99-
addImageProtocolsBlockCallbackUnsafe(
100-
reinterpret_cast<void *>(protocols.start), protocols.length);
101-
102-
if (sections->next == registered)
103-
break;
104-
sections = sections->next;
105-
}
106131
}
107132

108133
void swift::initializeProtocolConformanceLookup() {
109-
const swift::MetadataSections *sections = registered;
110-
while (true) {
111-
const swift::MetadataSectionRange &conformances =
112-
sections->swift5_protocol_conformances;
113-
if (conformances.length)
114-
addImageProtocolConformanceBlockCallbackUnsafe(
115-
reinterpret_cast<void *>(conformances.start), conformances.length);
116-
117-
if (sections->next == registered)
118-
break;
119-
sections = sections->next;
120-
}
121134
}
122135

123136
void swift::initializeTypeMetadataRecordLookup() {
124-
const swift::MetadataSections *sections = registered;
125-
while (true) {
126-
const swift::MetadataSectionRange &type_metadata =
127-
sections->swift5_type_metadata;
128-
if (type_metadata.length)
129-
addImageTypeMetadataRecordBlockCallbackUnsafe(
130-
reinterpret_cast<void *>(type_metadata.start), type_metadata.length);
131-
132-
if (sections->next == registered)
133-
break;
134-
sections = sections->next;
135-
}
136137
}
137138

138139
void swift::initializeDynamicReplacementLookup() {
139140
}
140141

141142
void swift::initializeAccessibleFunctionsLookup() {
142-
const swift::MetadataSections *sections = registered;
143-
while (true) {
144-
const swift::MetadataSectionRange &functions =
145-
sections->swift5_accessible_functions;
146-
if (functions.length)
147-
addImageAccessibleFunctionsBlockCallbackUnsafe(
148-
reinterpret_cast<void *>(functions.start), functions.length);
149-
150-
if (sections->next == registered)
151-
break;
152-
sections = sections->next;
153-
}
154143
}
155144

156145
#ifndef NDEBUG
@@ -173,16 +162,31 @@ const swift::MetadataSections *swift_getMetadataSection(size_t index) {
173162
}
174163

175164
SWIFT_RUNTIME_EXPORT
176-
const char *swift_getMetadataSectionName(void *metadata_section) {
165+
const char *
166+
swift_getMetadataSectionName(const swift::MetadataSections *section) {
177167
swift::SymbolInfo info;
178-
if (lookupSymbol(metadata_section, &info)) {
168+
if (lookupSymbol(section, &info)) {
179169
if (info.fileName) {
180170
return info.fileName;
181171
}
182172
}
183173
return "";
184174
}
185175

176+
SWIFT_RUNTIME_EXPORT
177+
void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
178+
void const **out_actual,
179+
void const **out_expected) {
180+
swift::SymbolInfo info;
181+
if (lookupSymbol(section, &info)) {
182+
*out_actual = info.baseAddress;
183+
} else {
184+
*out_actual = nullptr;
185+
}
186+
187+
*out_expected = section->baseAddress;
188+
}
189+
186190
SWIFT_RUNTIME_EXPORT
187191
size_t swift_getMetadataSectionCount() {
188192
if (swift::registered == nullptr)

stdlib/public/runtime/ImageInspectionCommon.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,35 @@
5252

5353
namespace swift {
5454
struct MetadataSections;
55-
static constexpr const uintptr_t CurrentSectionMetadataVersion = 1;
55+
static constexpr const uintptr_t CurrentSectionMetadataVersion = 2;
5656
}
5757

5858
struct SectionInfo {
5959
uint64_t size;
6060
const char *data;
6161
};
6262

63-
// Called by injected constructors when a dynamic library is loaded.
63+
/// Called by injected constructors when a dynamic library is loaded.
64+
///
65+
/// \param sections A structure describing the metadata sections in the
66+
/// newly-loaded image.
67+
///
68+
/// \warning The runtime keeps a reference to \a sections and may mutate it, so
69+
/// it \em must be mutable and long-lived (that is, statically or dynamically
70+
/// allocated.) The effect of passing a pointer to a local value is undefined.
6471
SWIFT_RUNTIME_EXPORT
65-
void swift_addNewDSOImage(const void *addr);
72+
void swift_addNewDSOImage(struct swift::MetadataSections *sections);
6673

6774
#ifndef NDEBUG
6875

6976
SWIFT_RUNTIME_EXPORT
70-
const char *swift_getMetadataSectionName(void *metadata_section);
77+
const char *
78+
swift_getMetadataSectionName(const struct swift::MetadataSections *section);
79+
80+
SWIFT_RUNTIME_EXPORT
81+
void swift_getMetadataSectionBaseAddress(
82+
const struct swift::MetadataSections *section,
83+
void const **out_actual, void const **out_expected);
7184

7285
SWIFT_RUNTIME_EXPORT
7386
size_t swift_getMetadataSectionCount();

stdlib/public/runtime/ImageInspectionMachO.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ using mach_header_platform = mach_header;
5454
#endif
5555

5656
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
57-
void CONSUME_BLOCK(const void *start, uintptr_t size)>
57+
void CONSUME_BLOCK(const void *baseAddress,
58+
const void *start, uintptr_t size)>
5859
void addImageCallback(const mach_header *mh) {
5960
#if __POINTER_WIDTH__ == 64
6061
assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!");
@@ -70,17 +71,19 @@ void addImageCallback(const mach_header *mh) {
7071
if (!section)
7172
return;
7273

73-
CONSUME_BLOCK(section, size);
74+
CONSUME_BLOCK(mh, section, size);
7475
}
7576
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
76-
void CONSUME_BLOCK(const void *start, uintptr_t size)>
77+
void CONSUME_BLOCK(const void *baseAddress,
78+
const void *start, uintptr_t size)>
7779
void addImageCallback(const mach_header *mh, intptr_t vmaddr_slide) {
7880
addImageCallback<SEGMENT_NAME, SECTION_NAME, CONSUME_BLOCK>(mh);
7981
}
8082

8183
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
8284
const char *SEGMENT_NAME2, const char *SECTION_NAME2,
83-
void CONSUME_BLOCK(const void *start, uintptr_t size,
85+
void CONSUME_BLOCK(const void *baseAddress,
86+
const void *start, uintptr_t size,
8487
const void *start2, uintptr_t size2)>
8588
void addImageCallback2Sections(const mach_header *mh) {
8689
#if __POINTER_WIDTH__ == 64
@@ -106,11 +109,12 @@ void addImageCallback2Sections(const mach_header *mh) {
106109
if (!section2)
107110
size2 = 0;
108111

109-
CONSUME_BLOCK(section, size, section2, size2);
112+
CONSUME_BLOCK(mh, section, size, section2, size2);
110113
}
111114
template <const char *SEGMENT_NAME, const char *SECTION_NAME,
112115
const char *SEGMENT_NAME2, const char *SECTION_NAME2,
113-
void CONSUME_BLOCK(const void *start, uintptr_t size,
116+
void CONSUME_BLOCK(const void *baseAddress,
117+
const void *start, uintptr_t size,
114118
const void *start2, uintptr_t size2)>
115119
void addImageCallback2Sections(const mach_header *mh, intptr_t vmaddr_slide) {
116120
addImageCallback2Sections<SEGMENT_NAME, SECTION_NAME,

0 commit comments

Comments
 (0)