GCC&x2B;C:在二进制文件中保持函数有序

GCC&x2B;C:在二进制文件中保持函数有序,c,gcc,function-pointers,microcontroller,C,Gcc,Function Pointers,Microcontroller,我正在为微控制器编写一些代码,我需要根据函数指针查找数据(这些数据和函数将在ROM中) 我希望能够相对快速地完成这项工作,并且不使用RAM作为查找表。我能想到的最简单的方法就是进行二进制搜索 我只是把它作为一个例子,所以它可能会被破坏,但希望你能理解: void myFunction1() {} void myFunction2() {} void myFunction3() {} void myFunction4() {} // ... typedef struct { void *fu

我正在为微控制器编写一些代码,我需要根据函数指针查找数据(这些数据和函数将在ROM中)

我希望能够相对快速地完成这项工作,并且不使用RAM作为查找表。我能想到的最简单的方法就是进行二进制搜索

我只是把它作为一个例子,所以它可能会被破坏,但希望你能理解:

void myFunction1() {}
void myFunction2() {}
void myFunction3() {}
void myFunction4() {}
// ...

typedef struct {
  void *functionPtr;
  int myData[10];
} SearchData;

const SearchData mySearchData[] = {
 { &myFunction1, ... },
 { &myFunction2, ... },
 { &myFunction3, ... },
 { &myFunction4, ... },
 // ...
};

void doBinarySearch(void *func, int min, int max) {
  if (max<min) return;
  int mid = (min+max)/2;
  if (func < mySearchData[mid].functionPtr)
    doBinarySearch(func, min, mid-1);
  else if (func > mySearchData[mid].functionPtr)
    doBinarySearch(func, mid+1, max);
  else {
    // we found it!
  }
}

void realBinarySearch(void *func) {
  doBinarySearch(func, 0, (sizeof(mySearchData)/sizeof(SearchData))-1);
}
void myFunction1(){}
void myFunction2(){}
void myFunction3(){}
void myFunction4(){}
// ...
类型定义结构{
void*functionPtr;
int myData[10];
}搜索数据;
const SearchData mySearchData[]={
{&myFunction1,…},
{&myFunction2,…},
{&myFunction3,…},
{&myFunction4,…},
// ...
};
void-doBinarySearch(void*func、int-min、int-max){
if(最大mySearchData[mid].functionPtr)
doBinarySearch(函数,中间+1,最大值);
否则{
//我们找到了!
}
}
void realBinarySearch(void*func){
doBinarySearch(func,0,(sizeof(mySearchData)/sizeof(SearchData))-1;
}
然而,要使其发挥作用,
myFunction1
myFunction2
等需要在内存中一个接一个地排列(尽管不一定紧挨着一个)。我需要使用
-Os
编译所有内容,以便将其放入可用的ROM中,因此如何确保函数实际保持正确的顺序?

…否则,我如何重新排序
mySearchData
,使其与函数的顺序相匹配

我现在唯一能想到的是:

  • 构建整个过程,然后进行一个后处理步骤,对二进制文件中的数组进行排序——尽管非常不可移植
  • 构建一次,查看列表文件以确定函数的实际顺序,重新编写
    mySearchData
    并再次编译-但不能保证编译器是确定性的

但这两个听起来都不太好。

对这个问题的大致回答:

此链接
这很吓人,但很管用

编辑:
方法2对查找表进行分区:
逐字节分区,非常有效。您只需要一个初始化步骤。分配16个字节。读取数组中的所有元素。“&”用0x0F表示函数指针的第一个字节,并在产生的偏移量中增加插槽。 按照您刚刚计算的长度分配16个列表。 重新读取数组中的所有元素,这次将它们插入已分配的列表中,并使用16个字节作为指针放置位置的计数器。

顺便问一下,你有动态内存分配吗?我刚意识到你说的是8KiB。

好的,。我真的不明白为什么你需要一个函数指针来搜索函数。。。将数据放在函数中要简单得多,在这种情况下,函数也将被重新排序。但这是你的要求

好的,C代码中的gcc如下所示:

您可以通过添加以下内容将每个函数放置在其自己的部分中:

void f1() __attribute__((section(".text.1")));
void f1()
{
}

void f2() __attribute__((section(".text.2")));
void f2()
{
}

void f3() __attribute__((section(".text.3")));
void f3()
{
}
然后使用修改后的链接器脚本,如下所示:

 .text   :
  {
   ....
   *(.text.1)
   *(.text.2)
   *(.text.3)
   ... continues here ...
此外,在链接器脚本中还有更多的可能性对输入部分进行排序。查找ld描述以进行排序

从劳工处手册:
通常情况下,链接器会按照链接过程中看到的顺序放置与通配符匹配的文件和节。您可以通过使用SORT关键字进行更改,该关键字出现在括号中通配符模式之前(例如,SORT(.text*))。使用SORT关键字时,链接器将按名称按升序对文件或节进行排序,然后再将其放入输出文件。

但是作为一句话,我相信你有一个XY问题。我想你会做一些事情,排序功能和处理二进制搜索是你的解决方案。我相信没有这些黑客,原产地问题是可以解决的


这将是很好的得到你原来的问题

…或者,如果我生成了一个大的switch语句,编译器是否足够聪明来优化它?您对后处理的担心是,事情将不可移植——但似乎您提出的任何构建时解决方案都将不可移植(在某些情况下,如果您更新到较新的gcc,甚至可能会中断)。也许更好的解决方案是不使表为常量,而是使用一个初始化步骤在运行时对其进行排序。通常.AFAICT您这样做是为了将参数保存在一个表中,对吗?有多少个函数?您有使用链接器脚本排序的示例吗?我已经使用了一个自定义的,我可以标记所有我想排序的东西,作为需要进入的特定部分。感谢添加方法2-你建议提前分配列表?仍然有很多RAM—忽略分配开销,在那个示例中,100个函数的分配开销为1400字节(我的8192个函数中的一个)。初始化分区后,您可以删除初始列表。“很高兴解决您原来的问题!”这很好—谢谢!我将尝试在顶部发布更多关于该问题的信息,但看起来SORT至少能满足任何基于GCC的目标的需要。@GordonWilliams如果答案是您需要的,您可以接受:-)谢谢!