You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
1.9 KiB
92 lines
1.9 KiB
20 years ago
|
/*
|
||
|
* arch/alpha/lib/strlen_user.S
|
||
|
*
|
||
|
* Return the length of the string including the NUL terminator
|
||
|
* (strlen+1) or zero if an error occurred.
|
||
|
*
|
||
|
* In places where it is critical to limit the processing time,
|
||
|
* and the data is not trusted, strnlen_user() should be used.
|
||
|
* It will return a value greater than its second argument if
|
||
|
* that limit would be exceeded. This implementation is allowed
|
||
|
* to access memory beyond the limit, but will not cross a page
|
||
|
* boundary when doing so.
|
||
|
*/
|
||
|
|
||
|
#include <asm/regdef.h>
|
||
|
|
||
|
|
||
|
/* Allow an exception for an insn; exit if we get one. */
|
||
|
#define EX(x,y...) \
|
||
|
99: x,##y; \
|
||
|
.section __ex_table,"a"; \
|
||
|
.long 99b - .; \
|
||
|
lda v0, $exception-99b(zero); \
|
||
|
.previous
|
||
|
|
||
|
|
||
|
.set noreorder
|
||
|
.set noat
|
||
|
.text
|
||
|
|
||
|
.globl __strlen_user
|
||
|
.ent __strlen_user
|
||
|
.frame sp, 0, ra
|
||
|
|
||
|
.align 3
|
||
|
__strlen_user:
|
||
|
ldah a1, 32767(zero) # do not use plain strlen_user() for strings
|
||
|
# that might be almost 2 GB long; you should
|
||
|
# be using strnlen_user() instead
|
||
|
|
||
|
.globl __strnlen_user
|
||
|
|
||
|
.align 3
|
||
|
__strnlen_user:
|
||
|
.prologue 0
|
||
|
|
||
|
EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned)
|
||
|
lda t1, -1(zero)
|
||
|
insqh t1, a0, t1
|
||
|
andnot a0, 7, v0
|
||
|
or t1, t0, t0
|
||
|
subq a0, 1, a0 # get our +1 for the return
|
||
|
cmpbge zero, t0, t1 # t1 <- bitmask: bit i == 1 <==> i-th byte == 0
|
||
|
subq a1, 7, t2
|
||
|
subq a0, v0, t0
|
||
|
bne t1, $found
|
||
|
|
||
|
addq t2, t0, t2
|
||
|
addq a1, 1, a1
|
||
|
|
||
|
.align 3
|
||
|
$loop: ble t2, $limit
|
||
|
EX( ldq t0, 8(v0) )
|
||
|
subq t2, 8, t2
|
||
|
addq v0, 8, v0 # addr += 8
|
||
|
cmpbge zero, t0, t1
|
||
|
beq t1, $loop
|
||
|
|
||
|
$found: negq t1, t2 # clear all but least set bit
|
||
|
and t1, t2, t1
|
||
|
|
||
|
and t1, 0xf0, t2 # binary search for that set bit
|
||
|
and t1, 0xcc, t3
|
||
|
and t1, 0xaa, t4
|
||
|
cmovne t2, 4, t2
|
||
|
cmovne t3, 2, t3
|
||
|
cmovne t4, 1, t4
|
||
|
addq t2, t3, t2
|
||
|
addq v0, t4, v0
|
||
|
addq v0, t2, v0
|
||
|
nop # dual issue next two on ev4 and ev5
|
||
|
subq v0, a0, v0
|
||
|
$exception:
|
||
|
ret
|
||
|
|
||
|
.align 3 # currently redundant
|
||
|
$limit:
|
||
|
subq a1, t2, v0
|
||
|
ret
|
||
|
|
||
|
.end __strlen_user
|