我有一个开发板(imx 1024)来自于nxp,我编写了一个使用MCUxpresso的软件(nxp的IDE)。对于我的项目,我被要求介绍位置独立代码(PIC),长话短说,这将节省我们在空中安装固件更新时的几秒钟停机时间。
我首先创建了一个新的标准项目,以便弄脏我的手,更好地理解PIC是如何工作的。因此,在对链接器脚本进行了一些更改(将.got部分放在闪存中的某个位置,并将其定义为SRAM (VMA))并对启动代码进行一些修改之后,我终于开始了第一步的工作:我可以在我的mcu上运行编译为“位置独立代码”的代码。
显然,我还没有把它移到“任何”地点。但作为第一步,我很高兴。
我的下一步是,输入一些响应硬件中断的代码。我不知道为什么,但我觉得这可能很棘手。或者,也许我也想看到它起作用。对我来说不幸的是,它失败了。太难了。
简要阐述:
闪烁以供参考的任务。
static void main_task(void *params)
{
while (1)
{
GPIO1->DR ^= (1<<24);
vTaskDelay(100);
}
}现在,我尝试了很多事情,想弄清楚这件事,一条线索,一个模糊的原因,但我什么也没得到。将.got部分从ITC移到ITC,不要将其移动到sram,而是将其保存在闪存中(因为我还没有在闪存中移动代码)。似乎没有什么能改变这种行为。一旦我用-fPIC编译了freertos测试项目,它就会在任务调度程序启动时崩溃。
潜入一些细节
作为参考,链接器脚本修改:
.got : ALIGN(4)
{
__global_offset_table_flash_start__ = LOADADDR(.got) ;
__global_offset_table_itc_start__ = ADDR(.got) ;
*(.got* .got.*)
__global_offset_table_flash_end__ = . ;
} >SRAM_DTC AT>PROGRAM_FLASH附带注意:这是复制到SRAM_DTC (/aka是数据的优化内存,ITC是指令的优化内存(/aka函数)。我认为 .got部分包含指向数据的指针,.got.plt包含共享库的函数(我不使用共享库,因此没有.got.plt部分)。我在ITC和DTC中都尝试了.got部分。两者都以同样的方式失败。对我来说,将.got存储在DTC中是最有意义的。所以,我坚持这样做,直到我知道这些假设中的一些是错误的。
也可供参考,调整部分的ResetHandler。在启动代码中,我设置了用于PIC的r9寄存器。我还将.got部分复制到SRAM_DTC
// Ignore the volatile stuff, it makes debugging easier, if I don't,
// I see 'optimized out' in mcuxpresso which is making my life harder
// other than that, it serves no functional purpose
// volatile is casted away with const_cast<...>
volatile extern unsigned int __global_offset_table_flash_start__;
volatile extern unsigned int __global_offset_table_itc_start__;
volatile extern unsigned int __global_offset_table_flash_end__;
volatile unsigned int size;
unsigned int index;
unsigned int *global_offset_table_flash;
unsigned int *global_offset_table_itc;
unsigned int *global_offset_table_end_itc;
unsigned int global_offset_table_size;
__attribute__ ((naked, section(".after_vectors.reset")))
void ResetISR(void)
{
// Disable interrupts
__asm volatile ("cpsid i");
// Setup r9 used for PIC, and let it point to the location in flash first
__asm volatile ("LDR r9, = __global_offset_table_flash_start__");
// Set the stack pointer, AFTER we setup r9
__asm volatile ("MSR MSP, %0" : : "r" (&_vStackTop) : );
//
// Copy global offset table to ram
//
global_offset_table_flash = const_cast<unsigned int*>(&__global_offset_table_flash_start__);
global_offset_table_itc = const_cast<unsigned int*>(&__global_offset_table_itc_start__);
global_offset_table_end_itc = const_cast<unsigned int*>(&__global_offset_table_flash_end__);
size =
reinterpret_cast<unsigned int>(&__global_offset_table_flash_end__) -
reinterpret_cast<unsigned int>(&__global_offset_table_itc_start__);
global_offset_table_size = static_cast<unsigned int>(&__global_offset_table_flash_end__ - &__global_offset_table_itc_start__);
for (index = 0u; index < size/sizeof(unsigned int); ++index)
{
global_offset_table_itc[index] = global_offset_table_flash[index];
}
__asm volatile ("LDR r9, = __global_offset_table_itc_start__");
// ... rest of startup code, initializes VTOR and some other nxp generated stuff
// ... before it jumps to main()我知道真正的男人会在集会上这样做。我还没有足够的男子汉来参加简单的集会。我还可以想象,核心程序集人员可能不太熟悉这个c++。我很有信心,这段代码可以做它声称要做的事情。我一步一步地完成了这个过程。.got section通过uint32被uint32复制,并以SRAM结束。
跳转到主后就完成了。执行的代码很少。我配置我的LED引脚,创建一个包含大量堆栈的freertos任务,并启动调度程序。
static void main_task(void *params);
int main(void) {
/* Init board hardware. */
BOARD_ConfigMPU();
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitBootPeripherals();
#ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL
/* Init FSL debug console. */
BOARD_InitDebugConsole();
#endif
gpio_pin_config_t USER_LED_config = {
.direction = kGPIO_DigitalOutput,
.outputLogic = 0U,
.interruptMode = kGPIO_NoIntmode
};
/* Initialize GPIO functionality on GPIO_AD_B1_08 (pin 82) */
GPIO_PinInit(GPIO1, 24U, &USER_LED_config);
xTaskCreate(
main_task,
"main",
2000,
nullptr,
2,
nullptr );
vTaskStartScheduler();
return 0 ;
}启动调度程序时,代码会在mem错误上立即崩溃。
有没有人有过职位独立代码的经验,并认识到这种行为?有小费吗?有什么好的建议可以排除吗?
我可以分享任何与代码相关的信息。这只是在mcuxpresso中创建的一个标准的新c++项目。如果这有帮助的话,我甚至可以在github上分享整个项目。
非常感谢帮助/指针/提示!
发布于 2022-04-30 13:43:01
在freertos社区的帮助下,我解决了这个问题。
最后,我所要做的就是修改freertos端口,在那里初始化堆栈以恢复创建的堆栈上的r9。
StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
TaskFunction_t pxCode,
void * pvParameters )
{
/* Simulate the stack frame as it would be created by a context switch
* interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
* of interrupts, and to ensure alignment. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR; /* xPSR */
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* LR */
/* Save code space by skipping register initialisation. */
pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
/* A save method is being used that requires each task to maintain its
* own exec return value. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_EXC_RETURN;
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
//
// I added this part, as suggested by freertos members
//
// Patched freertos for supporting -fpic: Set the task's initial R9 value
__asm ("MOV %[result], R9"
: [result] "=r" (pxTopOfStack[9-4])
);
return pxTopOfStack;
}https://stackoverflow.com/questions/72016315
复制相似问题