@@ -109,7 +109,12 @@ macro_rules! define_rust_probestack {
109109//
110110// The ABI here is that the stack frame size is located in `%rax`. Upon
111111// return we're not supposed to modify `%rsp` or `%rax`.
112- #[ cfg( target_arch = "x86_64" ) ]
112+ //
113+ // Any changes to this function should be replicated to the SGX version below.
114+ #[ cfg( all(
115+ target_arch = "x86_64" ,
116+ not( all( target_env = "sgx" , target_vendor = "fortanix" ) )
117+ ) ) ]
113118global_asm ! ( define_rust_probestack!(
114119 "
115120 .cfi_startproc
@@ -163,6 +168,69 @@ global_asm!(define_rust_probestack!(
163168 "
164169) ) ;
165170
171+ // This function is the same as above, except that some instructions are
172+ // [manually patched for LVI].
173+ //
174+ // [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
175+ #[ cfg( all(
176+ target_arch = "x86_64" ,
177+ all( target_env = "sgx" , target_vendor = "fortanix" )
178+ ) ) ]
179+ global_asm ! ( define_rust_probestack!(
180+ "
181+ .cfi_startproc
182+ pushq %rbp
183+ .cfi_adjust_cfa_offset 8
184+ .cfi_offset %rbp, -16
185+ movq %rsp, %rbp
186+ .cfi_def_cfa_register %rbp
187+
188+ mov %rax,%r11 // duplicate %rax as we're clobbering %r11
189+
190+ // Main loop, taken in one page increments. We're decrementing rsp by
191+ // a page each time until there's less than a page remaining. We're
192+ // guaranteed that this function isn't called unless there's more than a
193+ // page needed.
194+ //
195+ // Note that we're also testing against `8(%rsp)` to account for the 8
196+ // bytes pushed on the stack orginally with our return address. Using
197+ // `8(%rsp)` simulates us testing the stack pointer in the caller's
198+ // context.
199+
200+ // It's usually called when %rax >= 0x1000, but that's not always true.
201+ // Dynamic stack allocation, which is needed to implement unsized
202+ // rvalues, triggers stackprobe even if %rax < 0x1000.
203+ // Thus we have to check %r11 first to avoid segfault.
204+ cmp $0x1000,%r11
205+ jna 3f
206+ 2:
207+ sub $0x1000,%rsp
208+ test %rsp,8(%rsp)
209+ sub $0x1000,%r11
210+ cmp $0x1000,%r11
211+ ja 2b
212+
213+ 3:
214+ // Finish up the last remaining stack space requested, getting the last
215+ // bits out of r11
216+ sub %r11,%rsp
217+ test %rsp,8(%rsp)
218+
219+ // Restore the stack pointer to what it previously was when entering
220+ // this function. The caller will readjust the stack pointer after we
221+ // return.
222+ add %rax,%rsp
223+
224+ leave
225+ .cfi_def_cfa_register %rsp
226+ .cfi_adjust_cfa_offset -8
227+ pop %r11
228+ lfence
229+ jmp *%r11
230+ .cfi_endproc
231+ "
232+ ) ) ;
233+
166234#[ cfg( target_arch = "x86" ) ]
167235// This is the same as x86_64 above, only translated for 32-bit sizes. Note
168236// that on Unix we're expected to restore everything as it was, this
0 commit comments