Skip to content

Commit c5fe5d8

Browse files
torvaldsH. Peter Anvin
authored andcommitted
x86: Replace assembly access_ok() with a C variant
It turns out that the assembly variant doesn't actually produce that good code, presumably partly because it creates a long dependency chain with no scheduling, and partly because we cannot get a flags result out of gcc (which could be fixed with asm goto, but it turns out not to be worth it.) The C code allows gcc to schedule and generate multiple (easily predictable) branches, and as a side benefit we can really optimize the case where the size is constant. Link: http://lkml.kernel.org/r/CA%2B55aFzPBdbfKovMT8Edr4SmE2_=%2BOKJFac9XW2awegogTkVTA@mail.gmail.com Signed-off-by: H. Peter Anvin <hpa@zytor.com>
1 parent 661c801 commit c5fe5d8

File tree

1 file changed

+17
-11
lines changed

1 file changed

+17
-11
lines changed

arch/x86/include/asm/uaccess.h

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,28 @@
4040
/*
4141
* Test whether a block of memory is a valid user space address.
4242
* Returns 0 if the range is valid, nonzero otherwise.
43-
*
44-
* This is equivalent to the following test:
45-
* (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64)
46-
*
47-
* This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry...
4843
*/
44+
static inline int __chk_range_not_ok(unsigned long addr, unsigned long size, unsigned long limit)
45+
{
46+
/*
47+
* If we have used "sizeof()" for the size,
48+
* we know it won't overflow the limit (but
49+
* it might overflow the 'addr', so it's
50+
* important to subtract the size from the
51+
* limit, not add it to the address).
52+
*/
53+
if (__builtin_constant_p(size))
54+
return addr > limit - size;
55+
56+
/* Arbitrary sizes? Be careful about overflow */
57+
addr += size;
58+
return (addr < size) || (addr > limit);
59+
}
4960

5061
#define __range_not_ok(addr, size, limit) \
5162
({ \
52-
unsigned long flag, roksum; \
5363
__chk_user_ptr(addr); \
54-
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
55-
: "=&r" (flag), "=r" (roksum) \
56-
: "1" (addr), "g" ((long)(size)), \
57-
"rm" (limit)); \
58-
flag; \
64+
__chk_range_not_ok((unsigned long __force)(addr), size, limit); \
5965
})
6066

6167
/**

0 commit comments

Comments
 (0)