typeof and operands in named address spaces

Alexander Monakov amonakov@ispras.ru
Thu Nov 5 12:14:53 GMT 2020



On Thu, 5 Nov 2020, Uros Bizjak wrote:

> On Thu, Nov 5, 2020 at 12:38 PM Alexander Monakov <amonakov@ispras.ru> wrote:
> >
> > On Thu, 5 Nov 2020, Uros Bizjak via Gcc wrote:
> >
> > > > What is the usecase for stripping the address space for asm operands?
> > >
> > > Please see the end of [2], where the offset to <mem> is passed in %rsi
> > > to the call to this_cpu_cmpxchg16b_emu. this_cpu_cmpxchg16b_emu
> > > implements access with PER_CPU_VAR((%rsi)), which expands to
> > > %gs:(%rsi), so it is the same as %gs:<mem> in cmpxchg16b alternative.
> > > The offset is loaded by lea <mem>, %rsi to %rsi reg.
> >
> > I see, thanks. But then with the typeof-stripping-address-space solution
> > you'd be making a very evil cast (producing address of an object that
> > does not actually exist in the generic address space). I can write such
> > a solution, but it is clearly Undefined Behavior:
> >
> > #define strip_as(mem) (*(__typeof(0?(mem):(mem))*)(intptr_t)&(mem))
> >
> > void foo(__seg_fs int *x)
> > {
> >   asm("# %0" :: "m"(x[1]));
> >   asm("# %0" :: "m"(strip_as(x[1])));
> > }
> >
> > yields
> >
> > foo:
> >         # %fs:4(%rdi)
> >         # 4(%rdi)
> >         ret
> >
> >
> > I think a clean future solution is adding a operand modifier that would
> > print the memory operand without the segment prefix.
> 
> I was also thinking of introducing of operand modifier, but Richi
> advises the following:
> 
> --cut here--
> typedef __UINTPTR_TYPE__ uintptr_t;
> 
> __seg_fs int x;
> 
> uintptr_t test (void)
> {
>  uintptr_t *p = (uintptr_t *)(uintptr_t) &x;
>  uintptr_t addr;
> 
>  asm volatile ("lea %1, %0" : "=r"(addr) : "m"(*p));
> 
>  return addr;
> }

This is even worse undefined behavior compared to my solution above:
this code references memory in uintptr_t type, while mine preserves the
original type via __typeof. So this can visibly break with TBAA (though
the kernel uses -fno-strict-aliasing, so this particular concern wouldn't
apply there).

If you don't care about preserving sizeof and type you can use a cast to char:

#define strip_as(mem) (*(char *)(intptr_t)&(mem))

Alexander


More information about the Gcc mailing list