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: text/3543-patchable-function-entry.md
+69Lines changed: 69 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -91,6 +91,10 @@ Specifying any amount of padding other than 0 in an attribute will result in an
91
91
92
92
`#[unpatchable]` is a built-in alias for `#[patchable(prefix = 0, entry = 0)]`.
93
93
94
+
## Optimization Notes
95
+
96
+
Neither `#[patchable]` nor `-C patchable-function-entry` imply any restriction on inlining by themselves. If it is critical that patched code in the `entry` section be executed on *every* function invocation, not only in an advisory capacity, annotate the relevant functions with `#[inline(never)]` in addition.
97
+
94
98
# Drawbacks
95
99
[drawbacks]: #drawbacks
96
100
@@ -176,6 +180,71 @@ The primary disadvantage of this is having many ways to say the same thing.
176
180
177
181
I'm not sure why we would do this.
178
182
183
+
## Inlining
184
+
185
+
Inlining a function will prevent code in the `entry` patchable section from being executed. This raises the question of whether we should suppress or lint about inlining around this attribute or flag.
186
+
187
+
Existing support in `gcc` and `clang` does not suppress inlining at all, but `rustc` makes much heavier use of inlining than they do by default, making it possible that we might want to make a different call.
188
+
189
+
Linux's usage of this flag does not consider inlining suppression to be desirable. The two primary usages are:
190
+
191
+
- Hardening, where only indirect calls are considered, and so inlining is a non-issue
192
+
- Tracing, where inlined calls are explicitly out of scope, and `noinline` is already explicitly added to C code which should be traced.
193
+
194
+
Possible signals we could consider include beyond whether any padding is present:
195
+
196
+
- Whether the `entry` padding is nonzero, not considering `prefix` - `prefix` padding would not be executed by a direct call anyways
197
+
- Whether the padding was specified by an attribute or a flag
198
+
- Whether an explicit inlining annotation is present
199
+
200
+
Possible actions we could take include:
201
+
202
+
- Nothing
203
+
- Warning/linting
204
+
- Suppress inlining implicitly
205
+
206
+
Since we don't have a way to "reset" inlining to default, any plan involving suppression of inlining also needs to come with additional configuration to suppress the suppression.
207
+
208
+
### Inline suppresssion
209
+
If the function has nonzero `entry` padding, prevent inlining.
210
+
211
+
Add `-C allow-patchable-function-inlining` to disable this behavior.
212
+
213
+
Add `#[patchable(inlinable = yes)]` to suppress inline suppression in the attribute.
214
+
215
+
The advantage of this approach is that any instrumentation will always trigger when the function is called.
216
+
217
+
Disadvantages:
218
+
219
+
- When the flag is passed, we will disable inlining *nearly everywhere*. This would be disasterous for performance, given the number of functions Rust depends on inlining to optimize.
220
+
- This does not match C/C++ behavior, which means most existing use cases will be surprised.
221
+
- We need to add flag complexity to match existing use cases.
222
+
223
+
We could mitigate a portion of the disadvantages of this approach by only suppressing for the attribute rather than the flag. This would prevent the use of a flag to trace all function invocations.
224
+
225
+
### Lint on attribute
226
+
If the function has nonzero `entry` padding specified via attribute, and `#[inline]` is not explicitly set, trigger a lint.
227
+
228
+
Use `#[allow]` to accept the inlinability, the same as any other lint.
229
+
230
+
The advantage of this approach is that if the attribute is explicitly set, it will surface to the user to think about inlining. By using a lint, we avoid introducing new syntax, allow it to be ignored crate-wide if needed, and avoid user surprise.
231
+
232
+
Disadvantages:
233
+
234
+
- There are no instances of the C/C++ side variants of this attribute in the wild being used with nonzero entry padding, so we don't know if this behavior would actually be unexpected.
235
+
- There is no way for a user to use load-bearing entry padding on the whole program without annotating every function.
236
+
- The user would not be informed when patchability was triggered via a compilation flag.
237
+
238
+
### Do not suppress inlining (proposed)
239
+
Take no action on inlining other than mentioning it in the reference.
240
+
241
+
This approach mirrors what C/C++ does today. It doesn't close the door on taking the lint approach in the future, but we wouldn't be able to do suppression in the future without reversing the sense of the extra flags.
242
+
243
+
Disadvantages:
244
+
245
+
- There is no way for a user to use load-bearing entry padding on the whole program without annotating every function.
246
+
- Users not familiar with the C/C++ usage of the flag might be surprised when Rust's more aggressive inlining fails to run an `entry` prelude in some scenarios.
0 commit comments