gcc的内联汇编取全局变量地址

On September 16, 2012, in C语言, 语言学习, by sponge

最近在优化一段代码的过程中,用到了gcc的内联汇编。代码中有用到了许多全局变量,比如:

char mi[10]={...};

开始的时候,我对全局变量的取址是这样的:

__asm__ ("movq (%2, %1, 1 ), %0"
        :"=r"(cookie)
        :"r"(index),"r"(mi)
        );

在一个函数中使用这段代码,一条指令完成了对mi数组的访问,但同时也存在问题,即mi的地址会占用一个寄存器,mi的地址要在早先的时间内被装载到寄存器中(指令由编译器自动生成),同时,被mi占用的寄存器有些情况下不能被其他手工内联的汇编指令随便写入,编译器还没有那么智能帮你讲寄存器的内容保存好。

综上,使用这种方法会存在两方面问题:
1、使用至少两条指令来读取全局变量
2、正确性要小心呵护。

但是,在gcc的O2选项下访问mi变量的时候,因为全局变量的地址在编译时是可以确定的,所以这样的代码

int tmp = mi[3];

反汇编出来是

mov 0x405600(%eax), %ebx;

其中,eax中存的是index,也就是3,ebx是tmp。0x405600是全局变量mi的地址,在编译时就确定了这个地址,所以直接写在指令中了。

由于没系统的学过内联汇编的语法,所以不知道怎么在C语言中直接嵌入全局变量的地址,尝试了几种方法,用约束"P","I"什么的都不行,google也没查到相关的方法,后来在某开源代码中搜了下“(%%”,发现真有类似的方法,原来gcc的内联函数可以直接饮用c的标示符的,可以用下面的代码实现相同的功能:

__asm__ ("movq mi(%1 ), %0"
        :"=r"(cookie)
        :"r"(index)
        );

在我之前优化的代码中这么修改了之后,速度确实提升了一些。

anyShare分享到:
          
Tagged with:
 

3 Responses to “gcc的内联汇编取全局变量地址”

  1. 编译点滴 says:

    X86的嵌入式汇编不太清楚。但是GCC对于MIPS的嵌入式汇编支持直接将某个全局变量声明到某个指定的寄存器中。在调Linux Kernel的时候遇到过类似的问题。
    类似这种方式:
    register struct thread_info *__current_thread_info __asm__("$28");

    http://gcc.gnu.org/onlinedocs/gcc/Global-Reg-Vars.html#Global-Reg-Vars

    http://gcc.gnu.org/onlinedocs/gcc/Local-Reg-Vars.html#Local-Reg-Vars

    这两个链接可能有用

    • sponge says:

      @编译点滴 谢坤哥,这个是声明一个寄存器变量并指定某寄存器的,x86下局部变量可以但全局不可以,正确性是有编译器保证的。但这样大多数情况下会降低性能。。

  2. 久久星座约会 says:

    久久星座约会
    以星座为主题的网络约会,爱情交友,目前只加女生

    Q群:235893866

Leave a Reply

Note: Commenter is allowed to use '@User+blank' to automatically notify your reply to other commenter. e.g, if ABC is one of commenter of this post, then write '@ABC '(exclude ') will automatically send your comment to ABC. Using '@all ' to notify all previous commenters. Be sure that the value of User should exactly match with commenter's name (case sensitive).