92 lines
		
	
	
	
		
			1.9 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
		
		
			
		
	
	
			92 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
 |