广州游戏币团购: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()》.