广州游戏币团购:put_user
来源:百度文库 编辑:中财网 时间:2024/05/03 21:57:50
浅析put_user之__put_user_1,2,4,8,bad
文章来源:http://gliethttp.cublog.cn
使用put_user对1、2、4、8字节数据的用户空间和内核空间互拷贝,执行速度要远高于copy_from_user和copy_to_user所以当互传输数据数据为1、2、4、8字节时[小于8的数据,3,5,6,7可以硬凑成1、2、4、8以牺牲空间换取效率gliethttp].
1.put_user宏
/include/asm-arm/Uaccess.h
#define __put_user_x(__r1,__p,__e,__s,__i...) \
__asm__ __volatile__ ("bl __put_user_" #__s \
: "=&r" (__e) \//详见《浅析arm-linux内嵌汇编小程序》
: "0" (__p), "r" (__r1) \//p的寄存器作为输入直接赋值给r0寄存器
: __i) //告诉编译器:__i...等寄存器会在如下的应用中改变
#define put_user(x,p) \
({ \
const register typeof(*(p)) __r1 asm("r1") = (x); \//告诉编译器:寄存器r1存放x数据值[2007-07-17 gliethttp]
//如果数值为64位,那么编译器顺延r1,自动将r2作为高32位进行数据暂存
const register typeof(*(p)) *__p asm("r0") = (p); \//告诉编译器:寄存器r0存放p地址值
register int __e asm("r0"); \
switch (sizeof(*(p))) { \
case 1: \
__put_user_x(__r1, __p, __e, 1, "r2", "lr"); \//r0=p;r1=__r1;__e=r0;[gliethttp]
break; \
case 2: \
__put_user_x(__r1, __p, __e, 2, "r2", "lr"); \
break; \
case 4: \
__put_user_x(__r1, __p, __e, 4, "r2", "lr"); \
break; \
case 8: \
__put_user_x(__r1, __p, __e, 8, "ip", "lr"); \//64位,编译器自动将r2作为高32位进行数据暂存[gliethttp]
break; \
default: __e = __put_user_bad(); break; \
} \
__e; \
})
2.__put_user_1,__put_user_2,__put_user_4,__put_user_8,__put_user_bad
arch/arm/lib/putuser.S
__put_user_1,2,4,8,bad汇编源码:
.global __put_user_1
__put_user_1:
bic r2, sp, #0x1f00
bic r2, r2, #0x00ff
ldr r2, [r2, #TSK_ADDR_LIMIT] //读取current->addr_limit空间上限值
sub r2, r2, #1 //以上4句分析在另一篇《浅析armlinux-sp进程栈结构》专议
cmp r0, r2 //比较r0中的地址值和进程地址上限值
1: strlsbt r1, [r0] //在自身进程地址范围内,则执行赋值操作[gliethttp],把存放到r1寄存器中的x赋值
movls r0, #0 //r0 = 0;表示操作成功
movls pc, lr //返回
b __put_user_bad //p值不在本进程地址范围内,跳到bad
.global __put_user_2
__put_user_2:
bic r2, sp, #0x1f00
bic r2, r2, #0x00ff
ldr r2, [r2, #TSK_ADDR_LIMIT] //读取current->addr_limit空间上限值
sub r2, r2, #2 //以上4句分析在另一篇《浅析armlinux-SP进程栈结构》专议
cmp r0, r2 //比较r0中的地址值和进程地址上限值
2: strlsbt r1, [r0], #1 //16位赋值:低8字节赋值
movls r1, r1, lsr #8 //高8字节
3: strlsbt r1, [r0] //16位赋值:高8字节赋值
movls r0, #0 //r0 = 0;表示操作成功
movls pc, lr //返回
b __put_user_bad //p值不在本进程地址范围内,跳到bad
.global __put_user_4
__put_user_4:
bic r2, sp, #0x1f00
bic r2, r2, #0x00ff
ldr r2, [r2, #TSK_ADDR_LIMIT] //读取current->addr_limit空间上限值
sub r2, r2, #4 //以上4句分析在另一篇《浅析armlinux-SP进程栈结构》专议
cmp r0, r2 //比较r0中的地址值和进程地址上限值
4: strlst r1, [r0] //4字节赋值
movls r0, #0 //r0 = 0;表示操作成功
movls pc, lr //返回
b __put_user_bad //p值不在本进程地址范围内,跳到bad
.global __put_user_8
__put_user_8:
bic ip, sp, #0x1f00
bic ip, ip, #0x00ff
ldr ip, [ip, #TSK_ADDR_LIMIT] //读取current->addr_limit空间上限值
sub ip, ip, #8 //以上4句分析在另一篇《浅析armlinux-SP进程栈结构》专议
cmp r0, ip //比较r0中的地址值和进程地址上限值
5: strlst r1, [r0], #4 //低32位赋值
6: strlst r2, [r0] //r2存放高32位
movls r0, #0 //r0 = 0;表示操作成功
movls pc, lr //返回
/* fall through */
__put_user_bad:
mov r0, #-14 //空间超出current->addr_limit范围
mov pc, lr
注:使用语句ulimit -s 可以查看进程栈的最大值,一般8k.详见《浅析armlinux-sp进程切换栈结构和切换函数__switch_to()》.