如何将常量放在代码存储器中

时间:2013-02-01 13:31:25

标签: c++ c linux llvm x86-64

我需要以常数的形式保存程序中每个函数的一些信息。我想知道是否可以在代码存储器中将函数的常量放在它之前,所以如果通过函数指针调用函数,则可以通过减去函数指针的值来读取该信息。

为了进一步说明,我的代码存储器应如下所示。

ConstantForFunc1
Func1:
 ....

ConstantForFunc2
Func2:
 ....

以下是我将如何阅读该信息的示例代码

FuncPointer f = &Func2;
int constantForFunc2 = *((int*)(f - sizeof(int)));

请注意,使用哈希表对于我想要实现的目标来说太慢了,所以我需要一个非常快速的方法。所有这些修改,即插入常量和代码来从中读取,都是通过编译器传递来完成的,我正在编写并修改LLVM IR。使用结构对于编译器传递来说太麻烦了,因为它必须修改很多代码。

3 个答案:

答案 0 :(得分:6)

你正在做的事情没有意义,但是:

你可以使用结构吗?

struct example
{
  int constantForFunc;
  void (*ptrToFunc)();
};

//After declaring, maybe 3, functions

struct example funcList[3] = {{5, &func1}, {10, &func2}, {15, &func3}};

int currentFuncConstant=funcList[1].constantForFunc;
(*funcList[1].ptrToFunc)();

我没有使用函数指针说实话,probaby有错误。

答案 1 :(得分:0)

这根本不可接受吗?:

#include <iostream>

using namespace std;

const int Const__Fxn1 = 1;
void Fxn1()
{
  cout << "Fxn1" << endl;
}

const int Const__Fxn2 = 2;
void Fxn2()
{
  cout << "Fxn2" << endl;
}

#define GetFxnConst(FxnName) Const__ ## FxnName

int main()
{
  cout << GetFxnConst(Fxn1) << endl;
  cout << GetFxnConst(Fxn2) << endl;
  return 0;
}

选项2:

#include <iostream>
#include <cstring>

using namespace std;

const volatile int v1 = 0;
volatile unsigned v2 = 0;

void Fxn1()
{
  if (v1) { v2 = 0x12345601; }
  cout << "Fxn1" << endl;
}

void Fxn2()
{
  if (v1) { v2 = 0x12345602; }
  cout << "Fxn2" << endl;
}

int FindFxnConst(void(*f)())
{
  const unsigned char* p = (const unsigned char*)f;
  while (memcmp(p, "\x56\x34\x12", 3))
    p++;
  return p[-1];
}

int main()
{
  Fxn1();
  cout << FindFxnConst(Fxn1) << endl;
  Fxn2();
  cout << FindFxnConst(Fxn2) << endl;
  return 0;
}

输出(Ideone):

Fxn1
1
Fxn2
2

通过使用其他魔术前缀,您可以为每个函数嵌入8位以上的数据,例如:

  if (v1)
  {
    v2 = 0x12345611; // byte 1
    v2 = 0x789ABC22; // byte 2
    v2 = 0xDEF01233; // byte 3
    v2 = 0xFEDCBA44; // byte 4
  }

这不一定是可靠的解决方案,更不用说便携了。

答案 2 :(得分:0)

由于函数的地址是从可执行二进制文件中获知的(除非它们是从共享库中加载的),如果您关闭了地址空间布局随机化(ASLR),则可以使用gperf生成为您提供高效的哈希函数,并使用该哈希函数获取每个函数的常量。

但是,为此,您必须编译程序两次,首先从生成的二进制文件中获取函数的地址,以便您可以将这些地址作为gperf的输入并使用由gperf生成的哈希函数。但是必须要小心,第一次编译中的函数地址在第二次编译中不会有所不同。我不确定,如何实现这一点。

另一种方法是在加载程序后执行gperf之类的操作,这样就不需要编译两次了。但我不知道该怎么做。