如何从C ++代码中删除此汇编代码?

时间:2014-07-05 10:57:50

标签: c++ visual-studio assembly function-pointers

我的环境是Visual Studio 2008.

我有3个不同的库。总结一下,它们的行为等同如下。

图书馆1 - 提供要注册的功能

class FunctionRegistry
{
   typedef std::list<int> TListInt;
   TListInt m_Params;
   void * m_FPtr;
public:
   FunctionRegistry(void * fptr):m_FPtr(fptr){}
   FunctionRegistry& Insert(int value){m_Params.push_back(value); return *this;}
   void Call();
};

void FunctionRegistry::Call()
{
    /*this is the area I want to get rid of */
    TListInt::iterator ite = m_Params.begin();
    while (ite != m_Params.end());
    {
       __asm push *ite;//I want to remvoe this assmebly code somehow
       ++ite;//Edited after initial post
    }

    ((void(*)())m_FPtr)();

    ite = m_Params.begin();
    while (ite != m_Params.end());
    {
        int i = 0;
        __asm pop i;//I want to remvoe this assmebly code somehow
        ++ite;//Edited after initial post
    }
    /*end of area to get rid of*/
}

图书馆2 - 定义一组功能,例如

void foo(int i, int j)
{
    std::cout << "foo int int " << i << " " << j << std::endl;
}

void bar(int i)
{
    std::cout << "bar int " << i << std::endl;
}

void biz()
{
    std::cout << "biz" << std::endl;
}

FunctionRegistry fRegFoo((void*)&foo);
fRegFoo.Insert(10).Insert(20);

FunctionRegistry fRegBar((void*)&bar);
fRegBar.Insert(10);

FunctionRegistry fRegBiz((void*)&biz);

图书馆3 - 这是上述两个库的用户,示例用法如下,

fRegFoo.Call();
fRegBar.Call();
fRegBiz.Call();

这是遗留代码,我现在正在尝试摆脱上面的汇编代码。我可以轻松地更改(通过一些API更改)我的库1以满足我的需要。但我的问题是,由于库在大量用户中的大量分发,要求他们根据库1的API更改来改变他们的用例(这里是库3)应该是我的最后选择。

现在,我正在寻求你的帮助,有没有办法用任何可能的技术改变我的库1内部,而不用改变它的API来消除这个汇编代码?

如果您认为,如果没有任何API更改就无法实现,请建议对库3进行最少代码更改的方法。

4 个答案:

答案 0 :(得分:3)

如果您的最终用户只能按照“图书馆3”中的定义调​​用API,那么答案显然是肯定的。这个API的表面区域很小,如果没有任何汇编语言重新实现它将是微不足道的。这将需要更改Lib 2和Lib 1。

天真的实现是一组具有静态Call函数的类。还有很多其他选择。

但问题是:我们没有看到你要展示的一切。如果图书馆3中提供的API很丰富,和/或如果它是漏洞,那么答案可能是从“轻松”到“放弃并找到另一份工作”的任何地方。你的电话。


注意:这个答案基于你所说的:API Lib 3不能改变,但其他一切都可以。如果你需要一个解决方案,其中Lib 2和Lib 3都没有改变,只有Lib 1中的汇编代码可以改变,请编辑你的问题来解释这个。

如果是这样,有两种选择:符合标准或依赖于实现定义的行为。 [如果它只是Windows / VS的生活可能会更容易,但是20年前我做了这件事,所以我也可以将它移植到很多种类的Unix上。绝对可以做到。]

答案 1 :(得分:1)

这摆脱了asm push&amp; pop,但最终可能会有一个很大的switch语句,最多可达256 case-statements。 (可以使用宏来生成case语句吗?)

void FunctionRegistry::Call()
{
    typedef void (*_F)(...);
    _F f = (_F)m_FPtr;

    auto p=*m_Params.begin();
    switch(m_Params.size())
    {
        case 0: f();break;
        case 1: f(p); break;
        case 2: f(p, p+1); break;
        //...
        //case 256: f( ...please get therapy... ); break
    }
}

答案 2 :(得分:0)

不是100%肯定,但看起来你正在将值ite推到堆栈然后再将其弹出到i。如果这就是您要做的全部,请考虑使用std :: stack替换asm push / pop。类似的东西:

#include <stack>
//...
void FunctionRegistry::Call()
{
    std::stack<TListInt::value_type> astack;
    TListInt::iterator ite = m_Params.begin();
    while (ite != m_Params.end());
    {
       astack.push(*ite);
       ++ite;//Edited after initial post
    }

    ((void(*)())m_FPtr)();

    ite = m_Params.begin();
    while (ite != m_Params.end());
    {
        int i = astack.pop();
        ++ite;//Edited after initial post
    }
}

答案 3 :(得分:0)

你看过boost :: bind吗? 像这样:

#include <boost/bind/bind.hpp>
class FunctionRegistry
{
  typedef void tProcedure (void);

  private:
    const tProcedure proc;

  public:
    explicit FunctionRegistry( tProcedure proc ) : proc(proc) {}
    void Call() const { proc(); }

};

const FunctionRegistry fRegFoo( boost::bind( foo, 10, 20 ) );