4 ms·
It's great that Intel is adding a mode where indirect branches must land on specially encoded no-ops. Ideally, they'd also provide special encodings for "push
by KMag 5y ago
It's great that Intel is adding a mode where indirect branches must land on specially encoded no-ops. Ideally, they'd also provide special encodings for "push rbp" and "sub rsp, x" (for the -fomit-frame-pointer case) to cover the two most common first instructions in function prologues that could also be indirect branch targets.
Edit: actually, it would be best if indirect branches had to land on "special-nop", "push rbp" or "sub rsp, x" and future compilers needed to emit the new encodings for "special-push rbp" and "special-sub rsp, x" in the very few places they aren't used in function prologues. This would be better from a code density perspective, and might even allow one to turn the feature on without recompiling code and not have many applications break. I think backward compatibility would mostly depend on details of common jump table implementations (mostly C/C++ switch statements in cases where the density is such that compilers don't emit trees of conditional branches). I'm pretty sure the few users of GCC's "computed goto" (most notably CPython) would still need special no-ops at the start of each label.
Edit 2: is anyone aware of any common use of return where the target of the return isn't immediately after a call instruction? Return-oriented-programming for exploits is the main use case I'm aware of for returning to an address that isn't immediately after a call instruction. Unfortunately, checking this criterion in cases where the previous instruction is on another cache line would often cause extra cache misses.
- saagarjha 5y agoSome threaded interpreters do this, as it lets you use the return address branch predictor and continue control flow with just a ret.
- KMag 5y agoInteresting! My understanding of efficient direct-threaded interpreters is basically limited to Jones Forth. If I understand you correctly, these interpreters store their lists of subroutines in reverse order, set the stack pointer to the end of the list, and then everywhere jonesforth.s uses "lodsl\njmp *(%eax)" to iterate forward over a list of function pointers pointed to by %edi, these interpreters use "ret" to iterate backward over a list of function pointers pointed to by %esp. Is that correct? I take it these interpreters can't register any signal handlers, as at a minimum, the kernel would write a return address above the stack's "red zone" before invoking the signal handler, which would corrupt the code. Is that right?
- saagarjha 5y agoHere's an example: https://github.com/wishstudio/flinux/wiki/Dynamic-Binary-Translation#return-handling https://github.com/wishstudio/flinux/wiki/Dynamic-Binary-Tra.... You don't have to push everything to the stack, but that's definitely an option–it wouldn't interfere with the red zone because you'd be pushing in the opposite direction.
- rasz 5y ago> is anyone aware of any common use of return where the target of the return isn't immediately after a call instruction Bios before ram/cache initialization :) F000:00D2 ,BC 00D8 mov SP, offset data_82 ; (F000:00D8=0DAh) F000:00D5 E9 78CA jmp detect_CPU-type F000:00D8 00DA data_82 dw offset loc_5 F000:00DA loc_5: