1da177e4c3
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
91 lines
1.9 KiB
ArmAsm
91 lines
1.9 KiB
ArmAsm
/*
|
|
* 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
|