1.准备FlashDriver源码
需要实现Init、Erase、Write、Read接口,每个函数中不应出现子函数调用,可以使用内联修饰,确保生成的代码是位置无关的,否则无法实现在任意地址执行。
2.编译成.o或.a或可执行文件elf
3.对于第2步输出文件是.o或者.a,提取FlashDriver数据
使用binutils工具中objcopy、readelf和第三方srec_cat工具
1).readelf -t FlashDriver.o
;//获取4个操作段名,对于.o文件来说,一般未重定位的函数 以.text.FunName为段名,对应上述4个函数段名分别为 .text.Init,.text.Erase、.text.Write、.text.Read,所以,本步骤可省略。
2).objcopy -dump-section=text.Init=Init.bin FlashDriver.o
;//提取Init二进制指令数据,依次类推,提取Erase、Write、Read函数并保存为.bin文件,至此二进制数据已经提取为文件,根据需要把各个.bin文件转换为.srec、hex、或C语言数组
objcopy -I binary -O ihex FunName.bin FunName.hex;//转成bin->hex
objcopy -I binary -O srec FunName.bin FunName.srec;//转成bin->srec
srec_cat FunName.bin -binary FunName.c -c-array;//转成bin->c数组
4.对于第2步输出文件是可执行文件elf,提取FlashDriver数据
1).`objdump -x xxx.elf > dis.txt`;//获取各个函数符号**地址**及**长度**
2).`objcopy -O ihex xxx.elf output.hex`;//把elf转为output.hex
3).`srec_cat output.hex -intel -crop StartAddr EndAddr -o output.c -c-array`;//根据各个符号地址范围,提取二进制指令到c数组中,注意EndAddr不包括,比如起始地址0x0,长度为0x1,那么StartAddr和EndAddr为0x0 0x1
5.验证提取的指令是否可以使用
把C数组格式数据加载到工程中,以Erase为例
static uint8 FD_EraseData[] __attribute__((aligned(4), used)) = {擦除指令数据};
#ifdef USING_C_CALL
typedef uint8 (*FlsDrvFun_EraseType)(uint32);
FlsDrvFun_EraseType FlsDrvFun_Erase = (FlsDrvFun_EraseType )FD_EraseData + 1;//加1是因为C语言调用该函数会使用blx指令,地址为1进入thumb状态
#else//如果不+1,可以使用混编方式
uint8 FlsDrvFun_Erase(uint32 Addr)
{
uint8 res;
__asm volatile (
"mov r0, %1\n"
"mov r1, %2\n"
"orr r1, #1\n"
"blx r1\n"
"mov %0, r0\n"
: "=r"(res)
:"r"(Addr),"r"(FD_EraseData)
:"r0","r1","lr");
return res;
}
#endif