On Thu, Oct 15, 2020 at 09:09:11PM +0000, David Laight wrote: > From: Arvind Sankar > > Sent: 15 October 2020 19:14 > > > > Be clear about @ptr vs the variable that @ptr points to, and add some > > more details as to why the special barrier_data() macro is required. > > > > Signed-off-by: Arvind Sankar <nived...@alum.mit.edu> > > --- > > include/linux/compiler.h | 33 ++++++++++++++++++++++----------- > > 1 file changed, 22 insertions(+), 11 deletions(-) > > > > diff --git a/include/linux/compiler.h b/include/linux/compiler.h > > index 93035d7fee0d..d8cee7c8968d 100644 > > --- a/include/linux/compiler.h > > +++ b/include/linux/compiler.h > > @@ -86,17 +86,28 @@ void ftrace_likely_update(struct ftrace_likely_data *f, > > int val, > > > > #ifndef barrier_data > > /* > > - * This version is i.e. to prevent dead stores elimination on @ptr > > - * where gcc and llvm may behave differently when otherwise using > > - * normal barrier(): while gcc behavior gets along with a normal > > - * barrier(), llvm needs an explicit input variable to be assumed > > - * clobbered. The issue is as follows: while the inline asm might > > - * access any memory it wants, the compiler could have fit all of > > - * @ptr into memory registers instead, and since @ptr never escaped > > - * from that, it proved that the inline asm wasn't touching any of > > - * it. This version works well with both compilers, i.e. we're telling > > - * the compiler that the inline asm absolutely may see the contents > > - * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495 > > + * This version is to prevent dead stores elimination on @ptr where gcc and > > + * llvm may behave differently when otherwise using normal barrier(): > > while gcc > > + * behavior gets along with a normal barrier(), llvm needs an explicit > > input > > + * variable to be assumed clobbered. > > + * > > + * Its primary use is in implementing memzero_explicit(), which is used for > > + * clearing temporary data that may contain secrets. > > + * > > + * The issue is as follows: while the inline asm might access any memory it > > + * wants, the compiler could have fit all of the variable that @ptr points > > to > > + * into registers instead, and if @ptr never escaped from the function, it > > + * proved that the inline asm wasn't touching any of it. gcc only > > eliminates > > + * dead stores if the variable was actually allocated in registers, but > > llvm > > + * reasons that the variable _could_ have been in registers, so the inline > > asm > > + * can't reliably access it anyway, and eliminates dead stores even if the > > + * variable is actually in memory. > > I think I'd just say something like: > > Although the compiler must assume a "memory" clobber may affect all > memory, local variables (on stack) cannot actually be visible to the > asm unless their address has been passed to an external function. > So the compiler may assume such variables cannot be affected by > a normal asm volatile(::"memory") barrier(). > Passing the address of the local variables to the asm barrier > is enough to tell the compiler that the asm can 'see' the variables > (and spill anything held in registers to the stack) so that > the "memory" clobber has the expected effect. > > This is necessary to get llvm to do a memset() of on-stack data > at the end of a function to clear memory that contains secrets. > > David
I think it's helpful to have the more detailed explanation about register variables -- at first glance, it's a bit mystifying as to why the compiler would think that the asm can't access the stack. Spilling registers to the stack is actually an undesirable side-effect of the workaround.