本帖最后由 cruelfox 于 2019-6-23 15:22 编辑
我在跟踪 nortos (不使用TI RTOS)的工程时发现,在执行到 main() 之前,CPU执行过程中会转到 0x10000000 以后的代码去,显然这已经超出了 flash 的范围,只能是 ROM 中的代码了。那么,C程序是怎样调用ROM中的函数的?
TI 的工程,Reset handler 入口已经放在编译过的库里面了(SDK的 kernel/nortos/lib/nortos_cc13x2_v1.am4fg),不过也是有源代码供参考的,就是 kernel/nortos/startup/startup_cc13x2_cc26x2_gcc.c 里面。
void __attribute__((naked)) resetISR(void)
{
__asm__ __volatile__ (
" movw r0, #:lower16:resetVectors\n"
" movt r0, #:upper16:resetVectors\n"
" ldr r0, [r0]\n"
" mov sp, r0\n"
" bl localProgramStart"
);
}
很简单,设置堆栈指针后,直接转 localProgramStart() 函数执行。 后者在初始化 data, bss 之前,会调用两个函数:
IntMasterDisable();
/* Final trim of device */
SetupTrimDevice();
此处要补充一下,在编译后的代码中,实际上是调用 NOROM_CPUcpsid 和 NOROM_SetupTrimDevice 两函数,反汇编或者看ELF文件的符号表都能发现。函数名是怎么变的?原来是在一些 .h 文件里面,利用 #define 对名称进行了替换,结果就是同一套 C 程序可以编译出来不同版本的库,不同版本库里面的符号表(函数名)不同。如此做法可以防止库被混用,但对跟踪调试就造成一定的干扰了。
接下来,在 SetupTrimDevice() 函数里面(文件在 source/ti/devices/cc13x2_cc26x2_v1/driverlib/setup.c),
ThisLibraryIsFor_CC13x2_CC26x2_HwRev1x_HaltIfViolated();
// Enable standby in flash bank
HWREGBITW( FLASH_BASE + FLASH_O_CFG, FLASH_CFG_DIS_STANDBY_BITN ) = 0;
// Select correct CACHE mode and set correct CACHE configuration
#if ( CCFG_BASE == CCFG_BASE_DEFAULT )
SetupSetCacheModeAccordingToCcfgSetting();
#else
NOROM_SetupSetCacheModeAccordingToCcfgSetting();
#endif
我跟踪发现,SetupSetCacheModeAccordingToCcfgSetting() 是ROM中的代码。具体怎么实现?
在被 setup.c 包含的 setup_rom.h 中,有如下宏定义:
//*****************************************************************************
//
// Support for DriverLib in ROM:
// Redirect to implementation in ROM when available.
//
//*****************************************************************************
#if !defined(DRIVERLIB_NOROM) && !defined(DOXYGEN)
#include "../driverlib/rom.h"
...
#ifdef ROM_SetupSetCacheModeAccordingToCcfgSetting
#undef SetupSetCacheModeAccordingToCcfgSetting
#define SetupSetCacheModeAccordingToCcfgSetting ROM_SetupSetCacheModeAccordingToCcfgSetting
#endif
...
#endif
看出来是把函数名称替换成带 ROM_ 前缀的。然后找 rom.h 中的定义:
#define ROM_SetupSetCacheModeAccordingToCcfgSetting \
((void (*)(void)) \
ROM_API_SETUP_ROM_TABLE[18])
于是 SetupSetCacheModeAccordingToCcfgSetting() 成为了一个函数指针引用,入口地址在 ROM_API_SETUP_ROM_TABLE+18*4. 而根据
#define ROM_API_SETUP_ROM_TABLE ((uint32_t*) (ROM_API_TABLE[28]))
#define ROM_API_TABLE ((uint32_t *) 0x10000180)
得知 API 的定位是先从 0x10000180 也就是 API 总表的地址索引第29项得到 SETUP API 表的地址,再查 SETUP API 表的第19项获得 SetupSetCacheModeAccordingToCcfgSetting 函数入口地址。
在 GDB 里面验证一下:
(gdb) x /wx 0x10000180+28*4
0x100001f0: 0x100004bc
(gdb) x /wx 0x100004bc+18*4
0x10000504: 0x10004817
即 SetupSetCacheModeAccordingToCcfgSetting 函数位于 ROM 地址 0x10004816 处,与 GDB 跟踪执行看到的地址一致。
此外,在 setup_rom.c 里面实现了这个函数,不过编译时替换为带 NOROM_ 前缀的了,最终也没有被放到代码里面(不被引用,丢弃掉)。
此内容由EEWORLD论坛网友cruelfox原创,如需转载或用于商业用途需征得作者同意并注明出处