Asm代码的解释

7
以下是LuaJit的coco库中使用的GCC inline asm代码。能否提供一行一行的解释它所做的事情?
static inline void coco_switch(coco_ctx from, coco_ctx to)
{
  __asm__ __volatile__ (
    "movl $1f, (%0)\n\t" 
    "movl %%esp, 4(%0)\n\t" 
    "movl %%ebp, 8(%0)\n\t"
    "movl 8(%1), %%ebp\n\t" 
    "movl 4(%1), %%esp\n\t" 
    "jmp *(%1)\n" "1:\n"
    : "+S" (from), "+D" (to) : : "eax", "ebx", "ecx", "edx", "memory", "cc");
}

谢谢

2个回答

11

我的汇编语言知识有些模糊,但我认为我可以给你一个大致的概念。

ESP:堆栈指针,EBP:基址指针。

movl $1f, (%0)

将标签1的地址(在最后一行定义)移动到参数0(来自于)。

movl %%esp, 4(%0)

将寄存器ESP的内容移动到(from + 4)中。

movl %%ebp, 8(%0)

将寄存器EBP的内容移动到(from+8)。

movl 8(%1), %%ebp

将(to + 8)的内容移动到EBP寄存器中。

movl 4(%1), %%esp

将 (to + 4) 的内容移动到寄存器 ESP 中。

jmp *(%1)

跳转到(to)所包含的地址。

"1:"是一个跳转标签。

"+S"声明“源”(读取)参数,“+D”声明“目标”(写入)参数。语句末尾的寄存器列表是“破坏”列表,即ASM代码可能修改的寄存器列表,因此编译器可以采取措施来维护一致性(即不依赖例如ECX仍然包含与之前相同的值)。

我猜coco_ctx意味着“coco上下文”,因此:该函数将当前堆栈帧保存在“from”结构中,并将堆栈帧设置为在“to”结构中保存的内容。基本上,它从当前函数跳转到另一个函数。


3
没错,这不仅仅是从一个函数跳到另一个函数,而是从一个完整的调用栈跳到另一个调用栈;它完全切换了执行上下文。(此外,天哪,GCC内联汇编语法真奇怪。) - Crashworks
3
这是使用"C函数调用"语法包装的AT&T语法(http://wiki.osdev.org/Opcode_syntax),您可能不会相信,但我实际上比“标准”的Intel语法更喜欢它。;-) - DevSolar
上下文切换是否也适用于C++,还是我需要为thiscall编写一些不同的内容? - jameszhao00
1
这种上下文切换的方式适用于所有编译成机器代码并使用相同调用约定的语言。虽然这绝不是我的最佳领域,但它应该也适用于C++。 - DevSolar
这应该适用于使用任何常规调用约定(例如,cdecl、syscall、stdcall、pascal等)的x86程序。这就是汇编语言的美妙之处;它是所有编程语言的通用语言。需要注意的一件事是,来自调用者的EAX、EBX、ECX和EDX的内容应该被恢复,但我认为编译器会自动处理这个问题(因为它基本上必须为每个函数调用做到这一点)。 - Crashworks
2
我认为第一行可能是错误的。$1f 可能是下一个标签“1”在“向前”方向上的地址(请参见 https://dev59.com/zm865IYBdhLWcg3wR8ah)。 - nh2

2

DevSolar已经给出了正确的答案,我只想补充一下,你可以在这里了解有关EBP和ESP的更多信息。这些技术与IT相关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接