【问题标题】:Can I force g++ to pass floating number arguments on the stack?我可以强制 g++ 在堆栈上传递浮点数参数吗?
【发布时间】:2013-09-17 02:34:36
【问题描述】:

为了实现类似 C# 的调用方法,我需要将 C++ 代码与程序集结合起来。但是当我将浮点数传递给它时遇到了麻烦,发现这些参数是通过一些浮点指令传递的。

那么有什么办法可以强制 g++ 使用公共堆栈(esp)?谢谢。

【问题讨论】:

  • 它们不是在堆栈上传递,而是在寄存器上传递吗?
  • @PetrBudnik,这取决于您的 ABI 和调用约定。大多数 x86 ABI 在 FPU 堆栈上传递它们。大多数 x86_64 ABI 在 SSE 寄存器中传递它们。
  • 另外,这有点像XY problem。如果您可以提供更多上下文,很可能会有一个更简单的解决方案。
  • @zneak 但是如果我获取传递变量的地址?编译器必须将其溢出到堆栈中。
  • @PetrBudnik,我不确定我是否理解你的话。如果您确定获得其地址,则该变量必须存在于可寻址内存中,但这与调用约定无关。发出函数调用时,编译器并不关心变量是否存在于堆栈中:它需要以已知的方式传递值,以便被调用的函数可以检索它。

标签: c++ assembly g++


【解决方案1】:

从 cmets 来看,我认为您基本上是在尝试使用 std::functionstd::bind(来自 C++11)提供的类型安全功能可以实现的目标。

#include <functional>
#include <iostream>

using namespace std;

void foo(int x, double y, float z)
{
    cout << x << ", " << y << ", " << z << endl;
}

void call_agent(void* pointer)
{
    function<void()>* wrapper = reinterpret_cast<function<void()>*>(pointer);
    (*wrapper)();
    delete wrapper;
}

int main()
{
    function<void()>* callback = new function<void()>(bind(&foo, 1, 7.5, 8.4f));
    call_agent(callback);
}

只需将指向std::function&lt;void()&gt; 对象的指针传递给awake 函数(以及在您调用它们之后将delete 传递给它们)。 void() 作为模板参数意味着被包装的函数应该没有返回值并且不接受任何参数,您可以随意调整(int() 将是“int 返回值且无参数”,char(short, float) 将是“ char 返回值并接受一个short和一个float”等)

std::bind(Function, args...) 返回一个未指定类型的可调用对象。然后将传递给bind 的参数转发给函数。 std::function 包装了任何类型的可调用对象,包括函数指针和 std::bind 调用的结果,因此您无需担心所调用对象的类型。

更重要的是,如果您向bind 提供不正确的参数,您将得到编译时错误,而不必费力通过反汇编来找出问题所在。您还可以将复合类型传递给 bind(结构、联合),甚至是非 POD 类型。

【讨论】:

  • 这看起来很酷!但是我如何使用它从另一个线程调用呢?你的意思是我需要这样调用: void Invoke(function*) ,然后将其发送到绘图线程并调用它?
  • newing 对象的目的是获得指向它的指针。您可以将该指针传递给另一个线程,将其转换为function&lt;void()&gt;*,然后在其上使用调用运算符。我刚刚编辑了我的答案,以显示您如何将其传递给接受 void* 参数的函数。
  • 听起来不错!这似乎完美地解决了我的问题!现在我对std::bind和std::function的实现很感兴趣。非常感谢!
  • 奇怪的是,这样一个关于调用约定的低级问题不是由汇编或编译器指令解决,而是像函数对象这样的高级构造,只出现在最新的 C++ 标准中。
  • @C.R.,我明白你在说什么,但我的回答并没有解决在堆栈上传递实数的问题:相反,它解决了使用 pre- 调用任意函数的问题在另一个线程上指定参数。我希望这个答案教给任何人的最重要的事情是提出有关问题的问题,而不是尝试解决方案。 :)
【解决方案2】:

更改装配面以匹配。汇编不受调用约定的约束。

如果是第三方程序集,在程序集中构建一个代理函数,移动参数,然后跳转到真正的函数。

【讨论】:

  • 目前我正在使用这个原型:void Invoke(void*proc,int argnum, ...)。它包装数据并将它们传递给汇编代码。有了这些信息,恐怕我分不清浮点数和常用参数的区别。顺便说一句,没有第 3 方代码。
猜你喜欢
  • 2016-03-17
  • 1970-01-01
  • 2011-06-06
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多