Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions stdlib/public/SwiftShims/swift/shims/MetadataSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,15 @@ struct MetadataSections {
/// symbol in the image that contains these sections.
///
/// For Mach-O images, set this field to \c __dso_handle (i.e. the Mach header
/// for the image.) For ELF images, set it to \c __dso_handle (the runtime
/// will adjust it to the start of the ELF image when the image is loaded.)
/// For COFF images, set this field to \c __ImageBase.
/// for the image.) For ELF images, set it to \c __ehdr_start. For COFF
/// images, set this field to \c __ImageBase.
///
/// For platforms that have a single statically-linked image or no dynamic
/// loader (i.e. no equivalent of \c __dso_handle or \c __ImageBase), this
/// field is ignored and should be set to \c nullptr.
///
/// \bug When imported into Swift, this field is not atomic.
/// loader (i.e. no equivalent of \c __dso_handle, \c __ehdr_start, or
/// \c __ImageBase), this field is ignored and should be set to \c nullptr.
///
/// \sa swift_addNewDSOImage()
#if defined(__swift__) || defined(__STDC_NO_ATOMICS__)
const void *baseAddress;
#elif defined(__cplusplus)
std::atomic<const void *> baseAddress;
#else
_Atomic(const void *) baseAddress;
#endif

/// Unused.
///
Expand Down
70 changes: 3 additions & 67 deletions stdlib/public/runtime/ImageInspectionCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,67 +28,15 @@
#include "swift/Runtime/Concurrent.h"

#include <algorithm>
#include <atomic>
#include <cstdlib>

namespace swift {

static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;

/// Adjust the \c baseAddress field of a metadata sections structure.
///
/// \param sections A pointer to a valid \c swift::MetadataSections structure.
///
/// This function should be called at least once before the structure or its
/// address is passed to code outside this file to ensure that the structure's
/// \c baseAddress field correctly points to the base address of the image it
/// is describing.
static void fixupMetadataSectionBaseAddress(swift::MetadataSections *sections) {
bool fixupNeeded = false;

#if defined(__ELF__)
// If the base address was set but the image is an ELF image, it is going to
// be __dso_handle which is not the value we expect (Dl_info::dli_fbase), so
// we need to fix it up.
fixupNeeded = true;
#elif !defined(__MACH__)
// For non-ELF, non-Apple platforms, if the base address is nullptr, it
// implies that this image was built against an older version of the runtime
// that did not capture any value for the base address.
auto oldBaseAddress = sections->baseAddress.load(std::memory_order_relaxed);
if (!oldBaseAddress) {
fixupNeeded = true;
}
#endif

if (fixupNeeded) {
// We need to fix up the base address. We'll need a known-good address in
// the same image: `sections` itself will work nicely.
auto symbolInfo = SymbolInfo::lookup(sections);
if (symbolInfo.has_value() && symbolInfo->getBaseAddress()) {
sections->baseAddress.store(symbolInfo->getBaseAddress(),
std::memory_order_relaxed);
}
}
}
static Lazy<ConcurrentReadableArray<swift::MetadataSections *>> registered;
}

SWIFT_RUNTIME_EXPORT
void swift_addNewDSOImage(swift::MetadataSections *sections) {
#if 0
// Ensure the base address of the sections structure is correct.
//
// Currently disabled because none of the registration functions below
// actually do anything with the baseAddress field. Instead,
// swift_enumerateAllMetadataSections() is called by other individual
// functions, lower in this file, that yield metadata section pointers.
//
// If one of these registration functions starts needing the baseAddress
// field, this call should be enabled and the calls elsewhere in the file can
// be removed.
swift::fixupMetadataSectionBaseAddress(sections);
#endif
auto baseAddress = sections->baseAddress.load(std::memory_order_relaxed);
auto baseAddress = sections->baseAddress;

const auto &protocols_section = sections->swift5_protocols;
const void *protocols = reinterpret_cast<void *>(protocols_section.start);
Expand Down Expand Up @@ -144,9 +92,6 @@ void swift_enumerateAllMetadataSections(
) {
auto snapshot = swift::registered->snapshot();
for (swift::MetadataSections *sections : snapshot) {
// Ensure the base address is fixed up before yielding the pointer.
swift::fixupMetadataSectionBaseAddress(sections);

// Yield the pointer and (if the callback returns false) break the loop.
if (!(* body)(sections, context)) {
return;
Expand Down Expand Up @@ -180,11 +125,6 @@ const swift::MetadataSections *swift_getMetadataSection(size_t index) {
result = snapshot[index];
}

if (result) {
// Ensure the base address is fixed up before returning it.
swift::fixupMetadataSectionBaseAddress(result);
}

return result;
}

Expand All @@ -208,11 +148,7 @@ void swift_getMetadataSectionBaseAddress(const swift::MetadataSections *section,
} else {
*out_actual = nullptr;
}

// fixupMetadataSectionBaseAddress() was already called by
// swift_getMetadataSection(), presumably on the same thread, so we don't need
// to call it again here.
*out_expected = section->baseAddress.load(std::memory_order_relaxed);
*out_expected = section->baseAddress;
}

SWIFT_RUNTIME_EXPORT
Expand Down
35 changes: 31 additions & 4 deletions stdlib/public/runtime/SwiftRT-ELF-WASM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,40 @@
#include <cstddef>
#include <new>

#if SWIFT_STDLIB_HAS_DLADDR
#include <dlfcn.h>
#endif

#if defined(__ELF__)
extern "C" const char __dso_handle[];
extern "C" const char __ehdr_start[] __attribute__((__weak__));
#endif

static const void *getBaseAddress(void) {
#if defined(__ELF__)
if (&__ehdr_start != nullptr) {
return __ehdr_start;
}

#if SWIFT_STDLIB_HAS_DLADDR
// We've hit an edge case where the linker was invoked such that the ELF
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure about this? Can you point to the ELF specification where this would be the case? I believe that __ehdr_start is the edge case - it is a GNU extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both GNU binutils and LLVM's linker define it, and thus AFAICT Linux and FreeBSD define it. Android defines it too (see e.g. https://android.googlesource.com/platform/bionic/+/main/linker/linker_main.cpp). OpenBSD is an open question for me (no pun intended) which is why I pinged @3405691582 for assistance.

There appears to be chatter in the Google results about it either: not being defined when a linker script is used; or not being defined if the ELF header isn't in the same loadable section as the program headers. I'm having a fair bit of trouble actually getting concrete info here, which is why I've added this fallback path in the first place.

// header was not placed in a loadable section (or some such) and as a result
// __ehdr_start was not declared. Fall back to calling dladdr().
//
// NOTE: We cannot use SymbolInfo::lookup() here because this code is linked
// directly into each Swift binary rather than being exported from the Swift
// runtime.
Dl_info info;
if (dladdr(__dso_handle, &info)) {
return info.dli_fbase;
}
#endif
#elif defined(__wasm__)
// NOTE: Multi images in a single process is not yet
// stabilized in WebAssembly toolchain outside of Emscripten.
static constexpr const void *__dso_handle = nullptr;
// NOTE: Multi images in a single process is not yet stabilized in WebAssembly
// toolchain outside of Emscripten.
#endif
return nullptr;
}

#if SWIFT_ENABLE_BACKTRACING
// Drag in a symbol from the backtracer, to force the static linker to include
Expand Down Expand Up @@ -94,7 +121,7 @@ static void swift_image_constructor() {

::new (&sections) swift::MetadataSections {
swift::CurrentSectionMetadataVersion,
{ __dso_handle },
getBaseAddress(),

nullptr,
nullptr,
Expand Down