前言

开发了一款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);
01-08 13:36