前言
开发了一款debug不同芯片的类link工具。不同芯片的具体实现有不同的人员开发实现。那么就有可能出现不同人员修改一份代码的问题,极有可能会导致出现问题。为此采用一种新的方式,将指定的操作放在同一个段内。这样link底层的实现和业务逻辑的实现就彻底的分割出来。
旧的实现
首先需要在业务逻辑里面实现相应的处理函数,例如下面的代码。
void xx1_ops(void) {
...
}
void xx2_ops(void) {
...
}
然后在具体的调用函数里通过chip->name来区分不同芯片,然后执行对应的函数
void run(void) {
switch (chip->name) {
case xx1:
xx1_ops();
break;
case xx2:
xx2_ops();
break;
default:
braek;
}
}
这样的方式在开发人员少的时候很合适,方便。但是人员多了以后,芯片种类多了以后。没添加一个芯片就会修改run函数里面的内容,就可能会出现不确定的错误。所以需要采用更合适的方式。
新的实现
原理:最主要的就是要找到业务逻辑的函数入口。所以把所有函数入口放在统一的内存段中。run函数里面就从头到尾遍历,拿出要执行的是哪一个函数入口。这样run里面并不确定有哪些芯片,而业务逻辑也不需要修改run函数。从而很好的实现了隔离。
下面是在keil中实现的代码,在gcc环境下基本类似,只是段的定义和段首,段尾地址需要在ld文件中显示说明。
struct chip {
char name[8];
int ops;
};
#define SECTION __attribute__((used)) __attribute__((section("Chip")))
#define ADD_OPS(name,ops) \
SECTION const struct chip __chip_ops_##name = { \
#name,ops, \
} \
extern unsigned int Chip$$Base;
extern unsigned int Chip$$Limit;
struct chip * v;
for (v = (struct chip *)&(Chip$$Base);v < (struct chip *)&(Chip$$Limit)
;v++) {
LOG("%s\n",v->name);
}
上面SECTION的意思是告诉编译器这个变量我会使用,让编译器不要优化,同时把该变量放置在Chip段内。而Chip$$Base是该内存的首地址,Chip$$Limit是尾地址。通过遍历该段地址可实现查找指定函数入口的功能。
而在业务逻辑上,不需要关心link的底层实现,专注于实现逻辑后,使用下面的宏传递函数入口即可。
SC_ADD_CHIP(xxx,12);