A couple of years ago, I wrote and updated our MASM codebase with this macro below to combat Spectre V2.
NOSPEC_JMP MACRO target:REQ
PUSH target
JMP x86_indirect_thunk
ENDM
NOSPEC_CALL MACRO target:REQ
LOCAL nospec_call_start
LOCAL nospec_call_end
JMP nospec_call_end
ALIGN 16
nospec_call_start:
PUSH target
JMP x86_indirect_thunk
ALIGN 16
nospec_call_end:
CALL nospec_call_start
ENDM
.CODE
;; This is a special sequence that prevents the CPU speculating for indirect calls.
ALIGN 16
x86_indirect_thunk:
CALL retpoline_call_target
;; No benefit from aligning the capture_speculation branch target, as it is only potentially speculatively executed.
capture_speculation:
PAUSE
JMP capture_speculation
ALIGN 16
retpoline_call_target:
IFDEF WIN64
LEA RSP,[RSP+8]
ELSE
LEA ESP,[ESP+4]
ENDIF
RET
For example, here's some assembly code with speculation enabled (MST_QSPECTRE=1)
main PROC NEAR C
PUSH ESI
PUSH EDI
PUSH EBX
PUSH EBP
MOV EAX,OFFSET MyFun
;; Generated code to Call an indirect pointer without speculation.
IFDEF MST_QSPECTRE
NOSPEC_CALL EAX
ELSE
CALL EAX
ENDIF
POP EBP
POP EBX
POP EDI
POP ESI
RET
main ENDP
The disassembly shows how the speculative instructions are inserted
Question
In 2021, can I safely remove that MASM macro and rely upon CPU microcode updates etc.,... to resolve any Spectre concerns? For C code, looks like M$ and Linux C compilers have resolved it:
- Microsoft added /Qspectre to their MSVC compiler.
- GCC has compiler options for mitigating Spectre v2 via -mfunction-return, etc.,...
Thanks.