C 内联程序集-无用的中间副本指令
我正在尝试编写一个调度程序来运行我们所说的“光纤”。 不幸的是,我并不真正习惯于编写内联汇编C 内联程序集-无用的中间副本指令,c,assembly,inline-assembly,cpu-registers,mov,C,Assembly,Inline Assembly,Cpu Registers,Mov,我正在尝试编写一个调度程序来运行我们所说的“光纤”。 不幸的是,我并不真正习惯于编写内联汇编 typedef struct { //fiber's stack long rsp; long rbp; //next fiber in ready list struct fiber *next; } fiber; //currently executing fiber fiber *fib; 因此,第一项任务显然是为main功能创建一根光纤,使其可以挂
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 $24, %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
为什么要将mov
s编译成临时寄存器?我能设法摆脱它们吗
这个问题的第一个版本有来自gcc-O0
的asm输出,还有更多的指令和临时命令
启用优化并不能消除它们
打开它们并不能消除临时性
它确实消除了一些额外的负载和存储。fib
当然仍然存在于内存中,因为您将其声明为全局变量。rax
是来自malloc
的返回值,必须分配给内存中的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)
你启用了优化吗?@Jester我一开始没有,但启用它们并不能消除临时性(请参见上面的编辑)。C不支持方法为什么
rbp
专用于你的光纤?当然,您需要保存/恢复所有寄存器rsp
是唯一一个特殊的:您可以使用它来查找光纤堆栈(我假设您保存了其他寄存器)。@User1291:restorersp
,一次弹出所有其他寄存器,包括rbp
。轰,你回来了。如果恢复的函数使用了rbp
作为帧指针,则仍然是。您已从保存的上下文恢复,恢复除存储寄存器的内存之外的所有状态。(请记住,SystemV AMD64 ABI使用128B红色区域,因此在推送寄存器之前,您应该添加$-128,%rsp
,以便将它们保存在当前函数的红色区域下方。将状态弹出回regs后,sub$-128,%rsp
(imm8
中包含128,但+128不包含,因此为双负)您可能应该使用“=rm”
为编译器提供选项。在这种情况下,这无关紧要,但是如果您编写查看这些值的代码,编译器可以将它们保存在regs中,而不是执行存储->加载。(虽然理想情况下,有一种方法可以使C变量引用rbp
的值,而不使用任何指令。)如果给定多选项约束,Clang有时会做出错误的选择,因此请检查代码中的情况。(事实上,我不记得当我看到clang在GNUCasm
语句中表现不佳时的细节,但它可能会发生。)