From 6981effba5b529eacc8fc103bef3af1afe61635c Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 2 Jan 2025 14:16:36 -0500 Subject: [PATCH 1/4] Statically emit ELF notes for Swift's metadata sections. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ELF does not preserve section information like Mach-O and COFF do. This PR adds additional exported symbols on platforms that use ELF to help us find Swift's metadata sections at runtime. These symbols are emitted as [ELF notes](https://man7.org/linux/man-pages/man5/elf.5.html), which are a kind of optional metadata that can be iterated at runtime using the [`dl_iterate_phdr()`](https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html) function. Although the ELF standard says that notes can be stripped without affecting a program's behavior, in practice they are used widely for similar purposes e.g. by GCC/ld and various OS vendors. A more permanent solution may involve teaching llvm and lld about some new section name or attribute that translates to a specific custom ELF program header in the `PT_LOUSER`–`PT_HIUSER` range, then emitting that information for all of Swift's standard sections as well as anything marked `@_section`. Resolves #76698. --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 56 +++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index 032a97cd442e4..127d0e007b6a3 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -17,6 +17,13 @@ #include #include +#if defined(__ELF__) && __has_include() +#define EMIT_NOTES 1 +#include +#else +#define EMIT_NOTES 0 +#endif + #if defined(__ELF__) extern "C" const char __dso_handle[]; #elif defined(__wasm__) @@ -48,9 +55,56 @@ static const void *__backtraceRef __attribute__((used, retain)) BOUNDS_VISIBILITY extern const char __start_##name; \ BOUNDS_VISIBILITY extern const char __stop_##name; +#if EMIT_NOTES +/// A structure, compatible with the standard ELF note layout, that describes +/// the bounds of a section known to Swift. +/// +/// Sections described by these notes can be looked up at runtime using +/// `dl_iterate_phdr()` unless an image's notes have been stripped. +struct SectionNote { + /// The standard ELF note header. + ElfW(Nhdr) header; + + /// The name of the ELF note. + /// + /// The size of this array must be a multiple of `sizeof(void *)` plus `4` to + /// ensure correct alignment on 64-bit archs (because `ElfW(Nhdr)` is 12 bytes + /// long and only 4-byte aligned.) + char name[28]; + + /// The "payload" of the note. + struct Bounds { + /// The start address of the section. + const void *start; + + /// The end address of the section. + const void *end; + }; + + /// The bounds of the section. + Bounds bounds; +}; + +#define DECLARE_NOTE(name) \ + __attribute__((section(".note.swift5.section"))) \ + static const SectionNote note##name = { \ + { \ + sizeof(SectionNote::name), /* n_namesz */ \ + sizeof(Section::Bounds), /* n_descsz */ \ + 0 /* n_type (unused) */ \ + }, \ + #name, \ + &__start_##name, \ + &__stop_##name \ + }; +#else +#define DECLARE_NOTE(name) +#endif + #define DECLARE_SWIFT_SECTION(name) \ DECLARE_EMPTY_METADATA_SECTION(name, "aR") \ - DECLARE_BOUNDS(name) + DECLARE_BOUNDS(name) \ + DECLARE_NOTE(name) // These may or may not be present, depending on compiler switches; it's // worth calling them out as a result. From 529c74cd6f3a3244122eb543a30f2a7075ab566c Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 2 Jan 2025 16:50:19 -0500 Subject: [PATCH 2/4] Fix typos --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index 127d0e007b6a3..283ca81869b29 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -70,7 +70,7 @@ struct SectionNote { /// The size of this array must be a multiple of `sizeof(void *)` plus `4` to /// ensure correct alignment on 64-bit archs (because `ElfW(Nhdr)` is 12 bytes /// long and only 4-byte aligned.) - char name[28]; + char n_name[28]; /// The "payload" of the note. struct Bounds { @@ -85,17 +85,17 @@ struct SectionNote { Bounds bounds; }; -#define DECLARE_NOTE(name) \ - __attribute__((section(".note.swift5.section"))) \ - static const SectionNote note##name = { \ - { \ - sizeof(SectionNote::name), /* n_namesz */ \ - sizeof(Section::Bounds), /* n_descsz */ \ - 0 /* n_type (unused) */ \ - }, \ - #name, \ - &__start_##name, \ - &__stop_##name \ +#define DECLARE_NOTE(name) \ + __attribute__((section(".note.swift5.section"), used)) \ + static const SectionNote note_##name = { \ + { \ + sizeof(SectionNote::n_name), /* n_namesz */ \ + sizeof(SectionNote::Bounds), /* n_descsz */ \ + 0 /* n_type (unused) */ \ + }, \ + #name, \ + &__start_##name, \ + &__stop_##name \ }; #else #define DECLARE_NOTE(name) From fb0294f89741df255bdeb188c05d2657d13c717b Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 2 Jan 2025 17:31:51 -0500 Subject: [PATCH 3/4] Include a different header --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index 283ca81869b29..bc3e9305bf68e 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -17,9 +17,9 @@ #include #include -#if defined(__ELF__) && __has_include() +#if defined(__ELF__) && __has_include() #define EMIT_NOTES 1 -#include +#include #else #define EMIT_NOTES 0 #endif From eba788c3d8b9fa8f58595d424fe166d344179836 Mon Sep 17 00:00:00 2001 From: Jonathan Grynspan Date: Thu, 2 Jan 2025 18:14:25 -0500 Subject: [PATCH 4/4] Make n_name field larger sigh --- stdlib/public/runtime/SwiftRT-ELF-WASM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp index bc3e9305bf68e..bd1ce046566a5 100644 --- a/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp +++ b/stdlib/public/runtime/SwiftRT-ELF-WASM.cpp @@ -70,7 +70,7 @@ struct SectionNote { /// The size of this array must be a multiple of `sizeof(void *)` plus `4` to /// ensure correct alignment on 64-bit archs (because `ElfW(Nhdr)` is 12 bytes /// long and only 4-byte aligned.) - char n_name[28]; + char n_name[36]; /// The "payload" of the note. struct Bounds {