You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Documentation: [How to use Environment-Constrained Shared Libraries](https://github.com/swiftlang/swift-package-manager/blob/1eaf59d2facc74c88574f38395aa49983b2badcc/Documentation/ECSLs.md)
* Status: **Active review (September 22 ... October 6, 2025)**
5
+
* Status: **Accepted**
6
6
* Implementation: available in recent `main` snapshots under the experimental feature `SymbolLinkageMarkers` and with undercored attribute names `@_section` and `@_used`.
On top of specifying a custom section name with the `@section` attribute, marking a variable as `@used` is needed to prevent otherwise unused symbols from being removed by the compiler. When using section placement to e.g. implement linker sets, such values are typically going to have no usage at compile time, and at the same time they should not be exposed in public interface of libraries (not be made public), therefore we the need the `@used` attribute.
90
90
91
-
Different object file formats (ELF, Mach-O, COFF) have different restrictions and rules on what are valid section names, and cross-platform code will have to use different names for different file formats. To support that, custom section names can be specified as a string literal. The string will be used directly, without any processing, as the section name for the symbol. A new `#if objectFileFormat(...)` conditional compilation directive will be provided to support conditionalizing based on the file format:
91
+
Different object file formats (ELF, Mach-O, COFF) have different restrictions and rules on what are valid section names, and cross-platform code will have to use different names for different file formats. To support that, custom section names can be specified as a string literal. The string will be used directly, without any processing, as the section name for the symbol. A new `#if objectFormat(...)` conditional compilation directive will be provided to support conditionalizing based on the file format:
92
92
93
93
```swift
94
-
#ifobjectFileFormat(ELF)
94
+
#ifobjectFormat(ELF)
95
95
@section("mysection")
96
-
#elseifobjectFileFormat(MachO)
96
+
#elseifobjectFormat(MachO)
97
97
@section("__DATA,mysection")
98
98
#endif
99
99
var global =...
100
100
```
101
101
102
102
For the ELF file format specifically, the compiler will also emit a “section index” into produced object files, containing an entry about each custom section used in the compilation. This is a solution to an ELF specific problem where the behavior of ELF linkers and loaders means that sections are not easily discoverable at runtime.
103
103
104
-
When placing variables into a custom section, it's also allowed to use the `lazy` keyword to opt out of the mandatory static initialization and mandatory constant expression behavior, while still achieving section placement of the backing store of the data:
> Note: The intention is that the `@section` and `@used` attributes are to be used rarely and only by specific use cases; high-level application code should not need to use them directly and instead should rely on libraries, macros and other abstractions over the low-level attributes.
112
105
113
106
> The scope of this proposal is limited to compile-time behavior and compile-time control. We expect that full user-facing solutions for features like linker sets, test discovery or plugins will also require runtime implementations to discover and iterate the contents of custom sections, possibly from multiple modules. This proposal makes sure to provide the right building blocks and artifacts in binaries for the runtime components, but doesn’t prescribe the shape of those. However, it is providing a significant step towards generalized and safe high-level mechanisms for those use cases. See the discussion in [Runtime discovery of data in custom sections](#runtime-discovery-of-data-in-custom-sections) and [Linker sets, plugins as high-level APIs](#linker-sets-plugins-as-high-level-apis) in Future Directions.
@@ -183,6 +176,8 @@ When allowed, the `@section` attribute on a variable declaration has the followi
183
176
- Concretely, the section name string value will be set verbatim as a section specifier for the storage symbol at the LLVM IR level of the compiler. This means that any special behavior that the optimizer, the backend, the assembler or the linker applies based on known section names (or attributes specified as suffixes on the section name) will apply.
184
177
3. If applied to a global that is declared as part of top-level executable code (i.e. main.swift), the usual non-top-level-code initialization behavior is applied to the global. I.e. the variable is not sequentially initialized at startup.
185
178
179
+
The custom section name specified in the `@section` attribute is not validated by the compiler, instead it’s passed directly as a string to the linker.
180
+
186
181
When allowed, the `@used` attribute on a variable declaration has the following effect:
187
182
188
183
1. The storage symbol for the variable will be marked as “do not dead-strip”.
@@ -278,20 +273,9 @@ let a = (42, foo) // "foo" is statically initialized into a
278
273
// linkable/relocatable pointer
279
274
```
280
275
281
-
### Lazy variables with section placement
282
-
283
-
On global and static variables that are annotated with `@section`, the compiler will now allow the `lazy` keyword (which is currently disallowed on all global and static variables). Using it will opt such variable out of the "mandatory static initialization" behavior and instead use the at-runtime lazy initialization that traditional global and static variables have. The initializer expression does not need to be a constant expression in this case. This is useful for the uncommon use caseof placing variables into a custom section purely forcolocation (e.g. to improve performance by increasing page/cacheline locality):
Traditional global and static variables are backed by two symbols: An init-once token and the actual storage for the variable's content. Both of these symbols are going to be placed into the custom section when using `@section` with `lazy`. This also means that any offline or in-process introspection mechanisms cannot assume a specific layout or state of such variables and their storage bytes in the sections, as the exact layout and content of the symbols oflazy variables is an implementation detail of the Swift language runtime.
291
-
292
276
### Cross-platform object file format support
293
277
294
-
The custom section name specified in the `@section` attribute is not validated by the compiler, instead it’s passed directly as a string to the linker. Different platforms supported by Swift are using different object and binary file formats (Linux uses ELF, Darwin uses Mach-O, Windows uses COFF), and that implies different restrictions and rules on what are valid section names. Because of that, a multi-platform library code is expected to use `#ifos(...)` to use different section names for different platforms. Because of that, it’s expected that the attributes are to be typically only used indirectly via macros that hide the low-level nature of sections and object file formats from higher-level code developers:
278
+
Different platforms supported by Swift are using different object and binary file formats (Linux uses ELF, Darwin uses Mach-O, Windows uses COFF), and that implies different restrictions and rules on what are valid section names. Because of that, a multi-platform library code is expected to use `#ifos(...)` to use different section names for different platforms. Because of that, it’s expected that the attributes are to be typically only used indirectly via macros that hide the low-level nature of sections and object file formats from higher-level code developers:
295
279
296
280
```swift
297
281
// Example of a potential project-specific "@RegisterPlugin" macro:
@@ -311,17 +295,17 @@ let plugin = ...
311
295
312
296
See [Structured section specifiers](#structured-section-specifiers) below for more rationale.
313
297
314
-
In some cases, it’s not possible to differentiate on the OS to support multiple object file formats, for example when using Embedded Swift to target baremetal systems without any OS. For that, a new `#ifobjectFileFormat(...)` conditional compilation directive will be provided. The allowed values in this directive will match the setof supported object file formats by the Swift compiler (and expand as needed in the future). Currently, they exact values will be (case sensitive):
298
+
In some cases, it’s not possible to differentiate on the OS to support multiple object file formats, for example when using Embedded Swift to target baremetal systems without any OS. For that, a new `#ifobjectFormat(...)` conditional compilation directive will be provided. The allowed values in this directive will match the setof supported object file formats by the Swift compiler (and expand as needed in the future). Currently, they exact values will be (case sensitive):
315
299
316
300
* COFF
317
301
* ELF
318
302
* MachO
319
303
* Wasm
320
304
321
305
```swift
322
-
#ifobjectFileFormat(MachO)
306
+
#ifobjectFormat(MachO)
323
307
@section("__DATA_CONST,mysection")
324
-
#elseifobjectFileFormat(ELF)
308
+
#elseifobjectFormat(ELF)
325
309
@section("mysection")
326
310
#endif
327
311
let value =...
@@ -402,9 +386,9 @@ The notions of constant expressions and constant values is applicable to a much
402
386
The requirement to only use string literals as the section names could be lifted in the future, and we might allow referring to a declaration of variable with a compile-time string. This would be useful to avoid repetition when placing multiple values into the same section without needing to use macros.
403
387
404
388
```swift
405
-
#ifobjectFileFormat(ELF)
389
+
#ifobjectFormat(ELF)
406
390
let mySectionName ="mysection"// required to be a compile-time value
407
-
#elseifobjectFileFormat(MachO)
391
+
#elseifobjectFormat(MachO)
408
392
let mySectionName ="__DATA,mysection"// required to be a compile-time value
409
393
#endif
410
394
@@ -486,7 +470,7 @@ Because `@const` does not affect parsing or type resolution of the expression, i
486
470
487
471
In Mach-O, custom section names are written as a pair ofsegment (e.g. `__DATA`) +section (e.g. `mysection`). Structured section names with separate segment and section names, `@section(segment:"...", section:"...")` were considered instead, however this pattern does not generalize across object file formats, and is Mach-O specific (ELF and PE/COFF don’t have segments).
488
472
489
-
Because different object file formats impose different restrictions on custom section names (length, “.” prefix), a shorthand syntax to specify different section names for different object file formats was considered: `@section(ELF: “...”, MachO: “...”, COFF: “...”)`. This, however, has drawbacks of repeating the file format in cases where the code is only ever targeting a single format (common for example for embedded firmwares on ELF). The benefits of a shorthand syntax is marginal, given that we don’t expect normal application code to used the `@section` attribute directly but instead rely on macros or other higher-level API.
473
+
Because different object file formats impose different restrictions on custom section names (length, “.” prefix), a shorthand syntax to specify different section names for different object file formats was considered: `@section(ELF: “...”, MachO: “...”, COFF: “...”)`. This, however, has drawbacks of repeating the file format in cases where the code is only ever targeting a single format (common for example for embedded firmwares on ELF). The benefits of a shorthand syntax is marginal, given that we don’t expect normal application code to use the `@section` attribute directly but instead rely on macros or other higher-level API.
490
474
491
475
The alternative of using conditional compilation is what is expected to be used for those cases instead.
0 commit comments