Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15502677
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2007-07-19 14:40:43

浅析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().

阅读(3355) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2008-08-19 23:51:22

不错 http://hi.baidu.com/qrs1