当前位置: 首页 > 知识库问答 >
问题:

X64快速调用叶函数需要保留RCX吗?

充高扬
2023-03-14

我有一个用MASM64/ML64汇编的X64 ASM例程。它是一个独立的叶函数,而不是内联汇编。它用于Visual Studhtml" target="_blank">io解决方案中的C/C程序。

我发现了两个关于在MSDN上保留寄存器的参考资料:

  • 在内联程序集中使用和保存寄存器
  • 呼叫者/被叫方保存的寄存器。

第一种是用于内联装配,但它明确规定在使用__fastcall时保留 ECX。它似乎也缺乏对X64的处理,因为它指的是32位寄存器。

第二个告诉我们“RAX、RCX、RDX、R8、R9、R10、R11被认为是易失性的,必须在函数调用时被视为已销毁”。不幸的是,它没有明确说明它们是否需要保留。(如果你仔细看,它使用了误导而不是说明要采取的行动)。

我认为第二篇文章在这种情况下是控制性的,但我想弄清楚以避免混淆... X64 Fastcall Leaf函数是否需要保留CX/ECX/RCX?

共有2个答案

宰父保臣
2023-03-14

因为调用者必须假设函数销毁这些寄存器,所以被调用者可以销毁它们而不保留它们。也就是说,这些寄存器是易失性的,也称为call-clobbed。这将应用整个64位寄存器列表,包括所有arg传递寄存器。

内联__asm函数中与周围 C/C 代码的接口本质上与函数之间的 ABI/调用约定无关。例如,x86(32 位)快速呼叫具有调用 clobbered ECX,就像总是用于 arg-pass 寄存器一样。无论如何,32 位 fastcall 是独立于 Windows x64 fastcall 的调用约定,因此您阅读的有关 32 位 fastcall 的任何内容都不是 64 位的权威。

MSVC 内联 asm 支持非常脆弱,并且在编译器中实现了黑客,以至于他们需要您的 asm 在具有寄存器参数的函数中跳过箍,因为他们的编译器太笨了,无法像普通变量那样将它们保存在安全的地方。例如,您链接的文档说“这可能会在具有__asm块的函数中产生问题,因为函数无法判断哪个参数位于哪个寄存器中”,但这显然是无稽之谈,因为调用约定确定了这一点。否则,编译器无法使 asm 在不使用内联 asm 的函数中访问其参数。(或者,这是对编译器中的内联 asm 代码不是为处理 register-arg 调用约定而编写的,并且从未重写过这一事实的拙劣描述。其他编译器,包括clang-cl,没有这个问题。

这就是所有这些关于保留ECX的废话的来源,与函数在asm中相互调用的方式无关,如果您使用的是MSVC的脆性内联asm,则只是对函数内部的要求。

赖浩荡
2023-03-14

“在内联汇编中使用和保留寄存器”这篇文章只讨论x86,不适用于x86-64。

“调用者/被调用者保存的寄存器”这篇文章是关于x86-64调用约定的,并且明确指出RCX寄存器是易失的,因此不需要被调用者保存。

@rkhb的评论提到“x64调用约定概述”一文是混淆的根源,大概是因为它说:

x64只是使用__fastcall调用约定和基于RISC的异常处理模型

但是,如果您跟踪该引用中的< code>__fastcall链接,您会看到它说:“此调用约定[__fastcall]仅适用于x86体系结构”。我认为这篇概述文章实际上是想说,“x64使用了一种类似于< code>__fastcall的调用约定,其中寄存器用于传递参数”。

 类似资料:
  • 我得到了 错误:Route.Get()需要一个回调函数,但得到了一个[object Undefined] 这是我的路由文件: 错误日志: 错误:route.get()需要回调函数,但在route.(anonymous function)[as get](C:\users\PAI\DesktoP\mean\node_modules\express\lib\router\route.js:202:15

  • 对于我正在做的一些测试,我需要一个执行时间约为10秒的C#函数。它将从ASPX页面调用,但我需要该函数消耗服务器上的CPU时间,而不是呈现时间。对Northwinds数据库的缓慢查询或一些非常缓慢的计算将会工作。有什么想法吗?

  • 我在将这部分Java转换为Kotlin时遇到了问题: 方法的第二个参数(注意不是集合)接受。我尝试了几个解决方案,包括提供一个lambda: 但这导致: 错误:(32,38)Kotlin:意外标记 错误:(33,38)Kotlin:意外标记 错误:(31,56)Kotlin:类型不匹配:推断的类型是Kfunction1<@parametername mutablehttpresponse<>?,u

  • 问题内容: 因此,我们有一个页面: 并想添加一些点击事件: 奇迹般有效!但是,当您将第二个参数设为外部函数时: 它立即调用该函数。我该如何阻止! 问题答案: 由于第二个参数需要函数 引用 ,因此您需要提供一个。使用有问题的代码,您将立即调用该函数并传递其 结果(这是因为,因为该函数所做的全部是且不返回任何内容)。在匿名函数中调用该函数(如您的第一个示例),或者更改该函数以返回一个函数。

  • 问题内容: 在这里,它说,“注:意思是‘我不关心这个值’”,但是从JavaScript来了,我不明白是什么意思。 我可以打印这些功能的唯一方法是在参数前使用下划线: 没有下划线,我必须这样写,以避免出现任何错误: 我不理解此下划线用法。我何时,如何以及为什么使用这些下划线? 问题答案: 不同的用例有一些细微差别,但是通常下划线表示“忽略此”。 在声明一个新函数时,下划线告诉Swift调用时该参数不

  • 如何使用 一般云函数主要会涉及创建和触发两个操作 1.如何创建和编写云函数: 开发者可以登录到知晓云控制台,进入到引擎-云函数界面,知晓云提供了一个在线代码编辑器,你可以在上面编写你的云函数。目前编写云函数的渠道只有这里,后续我们会提供命令行功能上传云函数等渠道。 创建完云函数后为其编写逻辑代码,目前支持的编程语言仅有 Node.js,后续我们也会增加对其它语言的支持。 编写完代码,点击提交,你的