On Thu, Nov 5, 2020 at 1:16 PM Alexander Monakov via Gcc <gcc@gcc.gnu.org> wrote: > > > > On Thu, 5 Nov 2020, Uros Bizjak wrote: > > > On Thu, Nov 5, 2020 at 12:38 PM Alexander Monakov <amona...@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))
But in the end, on x86 the (uintptr_t)&x cast yields you exactly the offset from the segment register, no? The casting back to (uintrptr_t *) and the "dereference" is just because the inline asm is not able to build the lea otherwise? that said, sth like asm volatile ("lea fs:%1, %0" : "=r"(addr) : "r" ((uintptr_t)&x)); with the proper asm template should likely be used. Of course in case the kernel wants transparent handling of non-fs and fs-based cases that will be off. Richard. > > Alexander