内联汇编 - 无用的中间复制指令

inline assembly - useless intermediate copy instructions

我正在尝试为 运行 我们所说的 "fibers" 编写调度程序。 不幸的是,我不太习惯编写内联汇编。

typedef struct {
    //fiber's stack
    long rsp;
    long rbp;

    //next fiber in ready list
    struct fiber *next;

} fiber;

//currently executing fiber
fiber *fib;

所以第一个任务是 - 显然 - 为 main 函数创建一个纤程,以便它可以被挂起。

int main(int argc, char* argv[]){

    //create fiber for main function
    fib = malloc(sizeof(*fib));
    __asm__(
        "movq %%rsp, %0;"
        "movq %%rbp, %1;"
         : "=r"(fib->rsp),"=r"(fib->rbp)
         );

    //jump to actual main and execute
    __asm__(...);

}

这被编译为

    movl    , %edi   #,
    call    malloc  #
#APP
# 27 "scheduler.c" 1
    movq %rsp, %rcx;movq %rbp, %rdx;    # tmp92, tmp93
# 0 "" 2
#NO_APP
    movq    %rax, fib(%rip) # tmp91, fib
    movq    %rcx, (%rax)    # tmp92, MEM[(struct fiber *)_3].rsp
    movq    %rdx, 8(%rax)   # tmp93, MEM[(struct fiber *)_3].rbp

为什么要将 movs 编译成临时寄存器?我能以某种方式摆脱它们吗?

这个问题的第一个版本有来自 gcc -O0 的 asm 输出,有更多的指令和临时变量。

打开优化并不能消除它们。

turning them on does not get rid of the temporaries

它确实摆脱了一些额外的加载和存储。 fib 当然仍然存在于内存中,因为您将其声明为全局变量。 raxmalloc 中的 return 值,必须分配给内存中的 fib。另外两行写入您的 fib 成员,这也是必需的。

由于您指定了寄存器输出,因此 asm 块无法直接写入内存。不过,这很容易通过内存限制来解决:

__asm__(
    "movq %%rsp, %0;"
    "movq %%rbp, %1;"
     : "=m"(fib->rsp),"=m"(fib->rbp)
     );

这将生成:

    call    malloc
    movq    %rax, fib(%rip)
    movq    %rsp, (%rax)
    movq    %rbp, 8(%rax)