【问题标题】:How to put constants in code memory如何将常量放入代码存储器
【发布时间】:2013-02-01 13:31:24
【问题描述】:

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

为了进一步说明,我的代码记忆应该如下所示。

ConstantForFunc1
Func1:
 ....

ConstantForFunc2
Func2:
 ....

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

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

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

【问题讨论】:

  • 什么。不,你需要描述一个问题而不是描述一个解决方案。
  • 我认为你不能以便携的方式做到这一点。另外,为什么- 4?你有没有想过,指针可以有不同的大小?
  • 只有在编写嵌入式引导加载程序或非易失性存储器编程算法时,这样的代码才有意义。这就是你在做的吗?
  • 编译器会优化布局,因此在代码文件中的函数之前放置一个常量并不能保证它会在编译后的二进制文件中存在。
  • 典型的“XY”问题,你有一个问题,X,你认为应该通过做 Y 来解决,所以你问如何做 Y。描述你真正想要达到的目标,我们可能会有所帮助。

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


【解决方案1】:

你所做的还没有意义:

也许你可以使用结构体?

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)();

说实话我没用过函数指针,可能有错误。

【讨论】:

  • 我也是这么想的。
  • 是的,但这需要对代码进行大量更改,我正在编写编译器通行证。编写这么多修改代码的编译器传递是很困难的。
  • 还有一个包含常量或指向它们的可搜索数据结构。函数指针将是结构的键/索引。
  • Alexey,是的,可以使用哈希,但是对于我想要实现的目标来说,哈希很慢。
  • 在您的情况下,密钥已经是一个数字。所以你可以使用像func % 1000 甚至func << N >> N 这样非常简单的东西作为哈希函数。它会获取您的 func 地址的最后几位数字。如果函数位置很近,则冲突的可能性不大。
【解决方案2】:

这完全不能接受吗?:

#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
  }

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

【讨论】:

  • 实际上我的解决方案应该适用于函数指针。使用函数指针,您没有函数的名称,只有它的地址。
  • 知道了。但如果你保留名字的时间足够长,这可能会奏效。问题是,在某一时刻,无论如何你都会从函数名中获取函数地址。
【解决方案3】:

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

但是,为此,您必须编译程序两次,首先从生成的二进制文件中获取函数的地址,以便您可以将这些地址作为输入提供给gperf,然后使用哈希函数重新编译由gperf 生成。但是你必须小心,第一次编译的函数地址在第二次编译时不会变得不同。我不确定,如何实现。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    相关资源
    最近更新 更多