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
Copy file name to clipboardExpand all lines: proposals/0nnn-section-control.md
+49-58Lines changed: 49 additions & 58 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -62,7 +62,7 @@ This proposal recommends to use sections of the various object file formats as t
62
62
The proposal is to add two new attributes `@section` and `@used` that will allow annotating global and static variables with directives to place the value into a custom section, and to require no-dead-stripping aka "attribute used". The `@section` attribute relies heavily on the facilities provided by [Swift Compile-Time Values](https://github.com/artemcm/swift-evolution/blob/const-values/proposals/0nnn-const-values.md), namely the ability to enforce constantness of an expressions. Using `@section` requires that the initializer expression is a constant expression:
63
63
64
64
```swift
65
-
// Place entry into a section, mark as "do not dead strip".
65
+
// Place an entry into a section, mark as "do not dead strip".
66
66
// Initializer expression must be a constant expression.
67
67
// The global variable is implicitly made statically initialized.
68
68
@section("__DATA,mysection")
@@ -91,24 +91,14 @@ let myPlugin: PluginData = (
91
91
92
92
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.
93
93
94
-
A related new attribute, `@constInitialized` is to be added, which can be used to enforce that a global or static variable is statically initialized, without placing it into a custom section. Using attribute `@section` implies `@constInitialized`.
95
-
96
-
```swift
97
-
// Static initialization can be requested separately
98
-
@constInitialized
99
-
var fourPages =4*4096
100
-
```
101
-
102
-
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 either a string literal, or by referencing a constant global/static declaration that contains the name. The name will be directly set for the symbol in the resulting object file, without any processing. A new `#if objectFileFormat(...)` conditional compilation directive will be provided to support conditionalizing based on the file format:
94
+
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 name will be directly set for the symbol in the resulting object file, without any processing. A new `#if objectFileFormat(...)` conditional compilation directive will be provided to support conditionalizing based on the file format:
103
95
104
96
```swift
105
97
#if objectFileFormat(ELF)
106
-
@constlet mySectionName =".mysection"
98
+
@section(".mysection")
107
99
#elseif objectFileFormat(MachO)
108
-
@constlet mySectionName ="__DATA,mysection"
100
+
@section("__DATA,mysection")
109
101
#endif
110
-
111
-
@section(mySectionName)
112
102
var global =...
113
103
```
114
104
@@ -118,7 +108,7 @@ For the ELF file format specifically, the compiler will also emit a “section i
118
108
119
109
### Attributes @section and @used on global and static variables
120
110
121
-
Two new attributes are to be added: `@section`, which has a single argument specifying the section name, and a argument-less `@used` attribute. The section name must be either a string literal, or a reference to a constant string declaration.
111
+
Two new attributes are to be added: `@section`, which has a single argument specifying the section name, and a argument-less `@used` attribute. The section name must be a string literal. The attributes can be used either together or independently.
122
112
123
113
```swift
124
114
// (1)
@@ -127,32 +117,23 @@ Two new attributes are to be added: `@section`, which has a single argument spec
127
117
let global =...// ✅
128
118
129
119
// (2)
130
-
@constlet mySectionName ="__DATA,mysection"
131
-
132
-
@section(mySectionName)
120
+
@section("__DATA,mysection")
133
121
let global =...// ✅
134
122
135
123
// (3)
136
-
@section(Bool.rand() ?"a":"b")
137
-
let global =...// ❌
138
-
```
139
-
140
-
The section name must not be one of Swift’s runtime reserved sections (e.g. `__swift5_types`, etc.), such sections would be rejected:
141
-
142
-
```swift
143
-
@section("__TEXT,__swift5_types")
144
-
let global =...// ❌
124
+
@used
125
+
let global =...// ✅
145
126
```
146
127
147
128
The new attributes (`@section` and `@used`) can be used on variable declarations under these circumstances:
148
129
149
130
* the variable must be a global variable or a static member variable (no local variables, no non-static member variables)
150
131
* the variable must not be declared inside a generic context (either directly in generic type or nested in a generic type)
151
-
* the variable must be a stored property (not be a computed property)
132
+
* the variable must be a stored property (not a computed property)
152
133
* the variable must not have property observers (didSet, willSet)
153
134
* the initial expression assigned to the variable must be a constant expression, and it must be eligible for static initilization
154
135
155
-
*Note: These restrictions limit the `@section` and `@used` attributes to only be allowed on variables that are expected to be represented as exactly one statically-initialized global storage symbol (in the linker sense) for the variable’s content. This is generally true for all global and static variables in C and C++, but in Swift global variables might have zero global storage symbols (e.g. a computed property), or need non-trivial storage (e.g. lazily initialized variables with runtime code in the initializer expression).*
136
+
> *Note: These restrictions limit the `@section` and `@used` attributes to only be allowed on variables that are expected to be represented as exactly one statically-initialized global storage symbol (in the linker sense) for the variable’s content. This is generally true for all global and static variables in C and C++, but in Swift global variables might have zero global storage symbols (e.g. a computed property), or need non-trivial storage (e.g. lazily initialized variables with runtime code in the initializer expression).*
156
137
157
138
```swift
158
139
@section("__DATA,mysection") @used
@@ -201,31 +182,34 @@ The effects described above are applied to the storage symbols and don’t gener
201
182
202
183
### Guaranteed static initialization
203
184
204
-
Using attribute `@section` requires the initializer expression of the variable to be a constant expression. The `@const` annotation on the expression is not required (it’s implied). On top of the constant-ness, `@section` on a global or static variable enforces **static initialization** on that variable. The variable can be statically initialized, if the constant expression not only represents a valid compile-time constant, but also is able to be constant-folded into a representation that does not require any runtime initialization (pointer relocations/fixups done automatically by the loader are not considered runtime initialization for this purpose).
185
+
Using attribute `@section` requires the initializer expression of the variable to be a **constant expression**. It's not required to separately annotate the expression for being a compile-time expression, instead this is implied from the `@section` attribute. On top of the constant-ness, `@section` on a global or static variable enforces **static initialization** on that variable.
186
+
187
+
We consider the variable to be eligible for static initialization when:
205
188
206
-
This is a property that `@const` alone does not provide, but it’s necessary because we expect the data to be readable without any runtime mechanisms (i.e. reading raw bytes from the section at runtime, or offline binary inspection).
189
+
1. the initializer expression represents a valid compile-time constant, and
190
+
2. the initializer expression can be constant-folded into a representation that does not require any runtime initialization (pointer relocations/fixups done automatically by the loader are not considered runtime initialization for this purpose).
191
+
192
+
Not all constant expressions are necessarily statically initializable. For section placement we require the stronger property (static initialization) because we expect the data to be readable without any runtime mechanisms (i.e. reading raw bytes from the section at runtime, or offline binary inspection).
207
193
208
194
```swift
209
195
@section("__DATA,mysection")
210
196
let a =42// ✅
211
197
212
198
@section("__DATA,mysection")
213
-
letb=@const42//warning: @const is superfluous
199
+
letsectionPlaced=...expression...//✅, guaranteed to be statically initialized
214
200
215
201
@section("__DATA,mysection")
216
-
let sectionPlaced =...expression...// guaranteed to be statically initialized
217
-
218
-
let justConstant =@const...expression...// not guaranteed to be statically initialized
202
+
let notStaticallyInitializable =...expression that cannot be statically initialized...// ❌
219
203
```
220
204
221
-
*Note: As of this writing, all valid constant values are also eligible to be statically initialized, but we don’t expect that to hold in the future. So it’s important to distinguish between (a) a global variable being initialized with a language-level constant value (`@const`), and (b) a global variable that is guaranteed to be statically initialized. The difference can be subtle, and in some cases immaterial in practice, but future enhancements of constant values in Swift might take advantage of this difference — i.e. not all constant values are going to be statically initializable. Consider the following example: If a future language versions allows dictionary literals to be constant values, such values might not be statically initializable because of randomized hash seeding:*
205
+
> *Note: As of this writing, all valid constant values are also eligible to be statically initialized, but we don’t expect that to hold in the future. So it’s important to distinguish between (a) a global variable being initialized with a language-level constant value, and (b) a global variable that is guaranteed to be statically initialized. The difference can be subtle, and in some cases immaterial in practice, but future enhancements of constant values in Swift might take advantage of this difference — i.e. not all constant values are going to be statically initializable. Consider the following example: If a future language versions allows dictionary literals to be constant values, such values might not be statically initializable because of randomized hash seeding:*
222
206
223
-
```swift
224
-
let d1 =@const ["a":42, "b":777] // constant, but not statically initializable
225
-
let d2 =@const d1.count// statically initializable
226
-
```
207
+
> ```swift
208
+
>let d1 = ["a":42, "b":777] // constant, but not statically initializable
209
+
>let d2 = d1.count// statically initializable
210
+
>```
227
211
228
-
*However, using a statically non-initializable value in an expression does not preclude the outer expression from being statically initialized either. In this example, `d1` would not be allowed to be placed into a custom section because it’s not statically initializable. But `d2` could still potentially be statically initializable (even though the definition of `d2` uses a sub-expression that is not statically initializable), as it’s simply an integer.*
212
+
>*However, using a statically non-initializable value in an expression does not preclude the outer expression from being statically initialized either. In this example, `d1` would not be allowed to be placed into a custom section because it’s not statically initializable. But `d2` could still potentially be statically initializable (even though the definition of `d2` uses a sub-expression that is not statically initializable), as it’s simply an integer.*
229
213
230
214
As described in [Swift Compile-Time Values](https://github.com/artemcm/swift-evolution/blob/const-values/proposals/0nnn-const-values.md), values of function types are eligible for being compile-time evaluable. Their concrete pointer value is not fully known until link-time or program load-time (depending on type of linking, ASLR, PAC, etc.). For the purposes of guaranteed static initialization, function values are statically initialized into a function pointer. This pointer is still subject to normal linking and loading resolutions and fixups.
231
215
@@ -237,22 +221,6 @@ let a = (42, foo) // "foo" is statically initialized into a
237
221
// linkable/relocatable pointer
238
222
```
239
223
240
-
### Attribute `@constInitialized`
241
-
242
-
Static initialization of a global can be useful on its own, without placing data into a custom section. For that, a new attribute `@constInitialized` can be used. This attribute can be only used on variable declarations under the same conditions that `@section` and `@used` require (e.g. only on globals and statics, not in generic contexts, etc.)
243
-
244
-
```swift
245
-
@constInitialized
246
-
var fourPages =4*4096// ✅
247
-
248
-
structS {
249
-
@constInitialized
250
-
var fourPages =4*4096// ❌
251
-
}
252
-
```
253
-
254
-
The effect of this attribute is the same as of the `@section` attribute (static initialization, normal initalization behavior if top-level code) except the symbol is not actually placed into any custom sections.
255
-
256
224
### Cross-platform object file format support
257
225
258
226
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:
@@ -305,7 +273,7 @@ The goal of placing metadata into custom section is to make them discoverable bo
305
273
* In Wasm, dynamic linking is work in progress and not generally available yet.
306
274
* In ELF, however, section bounds are not guaranteed to be present in the address space at runtime, and in practice they are typically not present. This creates a challenge for retrieving section data in this configuration (ELF + multiple modules with dynamic linking) at runtime.
307
275
308
-
To solve this problem for the ELF object file format, the Swift compiler is going to emit a “**section index**” into every compilation that uses any symbols placed into a custom section. The index will be emitted only when producing ELF files, and consists of entries added into its own separate well-named section called `swift5_sections`. Each entry will have the following structure:
276
+
To solve this problem for the ELF object file format, the Swift compiler is going to emit a “**section index**” into every compilation that uses any symbols placed into a custom section. The index will be emitted only when producing ELF files, and consists of entries added into its own separate well-named section called `swift5_sections`. Each entry will have the following structure:
This will require some design decisions to be made around when should that be allowed, whether the attribute should be automatically inherited, and what exact behavior should we expect from the compiler around thunks, compiler-generated helper functions, getters and setters, etc.
Static initialization of a global can be useful on its own, without placing data into a custom section, and a separate attribute for that could be added. This way, one can get the same effects as the `@section` attribute (static initialization, normal initalization behavior if top-level code) except the symbol would not be actually placed into any custom section.
327
+
328
+
### Allowing a reference to a constant string declaration as a section name
329
+
330
+
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.
331
+
332
+
```swift
333
+
#ifobjectFileFormat(ELF)
334
+
let mySectionName =".mysection"// required to be a compile-time value
335
+
#elseifobjectFileFormat(MachO)
336
+
let mySectionName ="__DATA,mysection"// required to be a compile-time value
337
+
#endif
338
+
339
+
@section(mySectionName)
340
+
var global =...
341
+
```
342
+
356
343
### Runtime discovery of data in custom sections
357
344
358
345
As described in [ELF section index](#elf-section-index), accessing records in a custom section at runtime is heavily dependent on the object file format (ELF, Mach-O, Wasm, COFF), type oflinking (static vs dynamic) and available APIs from the operating system. For a single configuration, users can directly use an appropriate method of accessing the section data, and e.g. in embedded firmwares this might be completely fine as projects are commonly avoiding any attempts to be multi-platform or portable.
@@ -445,3 +432,7 @@ In a lot of the list code snippets in this proposal, both `@section` and `@used`
445
432
446
433
* `@section` and `@used` represent separate concepts and all combinations of them can be useful. An example of using `@section` without `@used` is to place for example a large data table from a library into its own section for binary size accounting reasons (so that it shows up separately in per-section binary size listings), but where we’d still expect the data table to be dead-code removed if not used.
447
434
* It’s already common to have those attributes as separate options in existing popular systems programming languages (C, C++, Rust).
435
+
436
+
### Blocking section placement into compiler reserved sections
437
+
438
+
In most cases, placing data into one of Swift’s runtime reserved sections (e.g. `__swift5_types`, etc.) without relying on extreme details of the compiler and runtime would result in invalid binaries. It was considered to simply reject using `@section` to target one of these reserved sections, but ultimately that would introduce both falsepositives (*what if we at some point wanted to write compiler/runtime code in Swift to actually legitimately place data into these sections?*) and falsenegatives (*there are many other "reserved" sections that the Swift compiler and language cannot know about*), and is thus left out of this proposal.
0 commit comments