【简介】
今天在查看以下,基于GCC 的FreeRtos 的适配代码中发现了 .ltorg 的指令,对于该指令不是很了解其意义。
static void prvPortStartFirstTask( void )
{
/* Start the first task. This also clears the bit that indicates the FPU is
* in use in case the FPU was used before the scheduler was started - which
* would otherwise result in the unnecessary leaving of space in the SVC stack
* for lazy saving of FPU registers. */
__asm volatile (
" ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n"
" ldr r0, [r0] \n"
" msr msp, r0 \n"/* Set the msp back to the start of the stack. */
" mov r0, #0 \n"/* Clear the bit that indicates the FPU is in use, see comment above. */
" msr control, r0 \n"
" cpsie i \n"/* Globally enable interrupts. */
" cpsie f \n"
" dsb \n"
" isb \n"
" svc 0 \n"/* System call to start first task. */
" nop \n"
" .ltorg \n"
);
}查看了下GNU 的手册 对 ltorg 的描述如下:

.ltorg 是 GNU 汇编器(GAS)针对 ARM/Thumb 架构的伪指令,用来在当前位置生成一个“字面常量池”(literal pool)。当汇编代码中使用了 ldr r0, =0xE000ED08 这类“伪指令”装载常量时,真实做法是在附近放置常量数据,再用 PC 相对地址跳过去取;.ltorg 会强制把这些待生成的常量立即写到当前位置,从而刷新常量池。这样做能避免常量池距离当前指令过远导致 PC 相对寻址超出范围,也常作为函数末尾的规范写法,确保所有字面量都已落在可到达范围内。
上述内嵌汇编的代码编译后的代码如下:
005041D0 LDR R0, =VTOR_REG ; [PC, #32] [0x005041F4] =0xE000ED08 005041D2 LDR R0, [R0] 005041D4 LDR R0, [R0] 005041D6 MSR MSP, R0 005041DA MOV.W R0, #0 005041DE MSR CONTROL, R0 005041E2 CPSIE i 005041E4 CPSIE f 005041E6 DSB SY 005041EA ISB SY 005041EE SVC #0 005041F0 NOP $Data 005041F2 DC16 0x0000 $Data 005041F4 DC32 0xE000ED08 ; VTOR_REG
查看对应的对应的汇编代码也可以看出,在NOP 指令的后面放置了一个文字池来加载数据至R0寄存器。
本地修改代码删除函数末端的 .ltorg

修改后的编译器产生的代码,在函数的末端没有添加literal pool 而是放到如下地址。

我要赚赏金
