LINKER脚本GCC如何避免单板调用
LINKER script GCC how to avoid veneer call
我在项目中将一些函数从 FLASH 复制到 RAM 并调用它们。一切正常,除了我遇到的一个小问题 - 如果我直接调用函数,编译器会添加 veneer 调用(正确调用 RAM 中的函数)。
如果我通过指针调用它,一切都可以。调试器显示函数的解析地址是正确的。
#define RAMFCALL(func, ...) {unsigned (* volatile fptr)() = (unsigned (* volatile)())func; fptr(__VA_ARGS__);}
RAMFCALL(FLASH_EraseSector, 0, 0);
FLASH_EraseSector(0,0);
和相应的调用:
311 RAMFCALL(FLASH_EraseSector, 0, 0);
0801738e: ldr r3, [pc, #88] ; (0x80173e8 <flashSTMInit+140>)
08017390: str r3, [sp, #12]
08017392: ldr r3, [sp, #12]
08017394: movs r1, #0
08017396: mov r0, r1
08017398: blx r3
312 FLASH_EraseSector(0,0);
0801739a: movs r1, #0
0801739c: mov r0, r1
0801739e: bl 0x801e9f0 <__FLASH_EraseSector_veneer>
调试器显示正确的地址。
和链接描述文件的相应部分
OVERLAY : NOCROSSREFS
{
.RAM_functions
{
. = ALIGN(512);
RAM_functions_load = LOADADDR(.RAM_functions);
PROVIDE(RAM_VectorTable_start = .);
KEEP(*(.RAM_VectorTable))
KEEP(*(.RAM_VectorTable*))
PROVIDE(RAM_VectorTable_end = .);
. = ALIGN(4);
RAM_functions_start = .;
KEEP(*(.RAM_functions))
KEEP(*(.RAM_functions*))
RAM_functions_end = .;
. = ALIGN(4);
RAM_functionsDATA_start = .;
KEEP(*(.RAM_functionsDATA))
KEEP(*(.RAM_functionsDATA*))
RAM_functionsDATA_end = .;
. = ALIGN(4);
RAM_functionsBUFFER_start = .;
}
/* used by the startup to initialize data */
/* Initialized data sections goes into RAM, load LMA copy after code */
.data
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
}
}>RAM AT> FLASH
又是一个问题:如何去除贴面调用
我会自己回答,因为我找到了原因:)
bl指令相对PC是+=32MB。我是从 FLASH 调用 RAM 中的函数,实际距离远超过 32MB。所以链接器不得不放置单板函数调用。
可以通过向编译器提供 -mlong-calls 参数来消除胶合板。每个呼叫站点都会变得更长一些,从而失去一些性能,但是它可能仍然比在单板中失去性能更好。
还可以通过应用 long_call 属性将各个函数标记为通过寄存器调用(ARM 假设基于程序集,在 https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#ARM-Function-Attributes 中描述)
我在项目中将一些函数从 FLASH 复制到 RAM 并调用它们。一切正常,除了我遇到的一个小问题 - 如果我直接调用函数,编译器会添加 veneer 调用(正确调用 RAM 中的函数)。
如果我通过指针调用它,一切都可以。调试器显示函数的解析地址是正确的。
#define RAMFCALL(func, ...) {unsigned (* volatile fptr)() = (unsigned (* volatile)())func; fptr(__VA_ARGS__);}
RAMFCALL(FLASH_EraseSector, 0, 0);
FLASH_EraseSector(0,0);
和相应的调用:
311 RAMFCALL(FLASH_EraseSector, 0, 0);
0801738e: ldr r3, [pc, #88] ; (0x80173e8 <flashSTMInit+140>)
08017390: str r3, [sp, #12]
08017392: ldr r3, [sp, #12]
08017394: movs r1, #0
08017396: mov r0, r1
08017398: blx r3
312 FLASH_EraseSector(0,0);
0801739a: movs r1, #0
0801739c: mov r0, r1
0801739e: bl 0x801e9f0 <__FLASH_EraseSector_veneer>
调试器显示正确的地址。
和链接描述文件的相应部分
OVERLAY : NOCROSSREFS
{
.RAM_functions
{
. = ALIGN(512);
RAM_functions_load = LOADADDR(.RAM_functions);
PROVIDE(RAM_VectorTable_start = .);
KEEP(*(.RAM_VectorTable))
KEEP(*(.RAM_VectorTable*))
PROVIDE(RAM_VectorTable_end = .);
. = ALIGN(4);
RAM_functions_start = .;
KEEP(*(.RAM_functions))
KEEP(*(.RAM_functions*))
RAM_functions_end = .;
. = ALIGN(4);
RAM_functionsDATA_start = .;
KEEP(*(.RAM_functionsDATA))
KEEP(*(.RAM_functionsDATA*))
RAM_functionsDATA_end = .;
. = ALIGN(4);
RAM_functionsBUFFER_start = .;
}
/* used by the startup to initialize data */
/* Initialized data sections goes into RAM, load LMA copy after code */
.data
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
}
}>RAM AT> FLASH
又是一个问题:如何去除贴面调用
我会自己回答,因为我找到了原因:)
bl指令相对PC是+=32MB。我是从 FLASH 调用 RAM 中的函数,实际距离远超过 32MB。所以链接器不得不放置单板函数调用。
可以通过向编译器提供 -mlong-calls 参数来消除胶合板。每个呼叫站点都会变得更长一些,从而失去一些性能,但是它可能仍然比在单板中失去性能更好。 还可以通过应用 long_call 属性将各个函数标记为通过寄存器调用(ARM 假设基于程序集,在 https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#ARM-Function-Attributes 中描述)