无法使用 IAR ARM 编译器将函数表强制到特定地址

Posted

技术标签:

【中文标题】无法使用 IAR ARM 编译器将函数表强制到特定地址【英文标题】:Can't force function table to specific address with IAR ARM compiler 【发布时间】:2016-06-25 12:30:46 【问题描述】:

我有一个这样定义的函数表类型

typedef struct

    uint16_t majorRevision;
    uint16_t minorRevision;
    uint8_t  (*CommInit)(void *);
    uint8_t  (*CommDeInit)(void);
    uint16_t (*Write)(uint8_t *, uint16_t);
    uint16_t (*Read)(uint8_t *, uint16_t);
    uint8_t  (*Attached)(void);
    uint8_t  (*ExitApp)(uint8_t);
    uint8_t  (*Jump)(uint32_t address);
    uint16_t (*GetCRC)(uint8_t*, uint32_t);
    int      (*Encrypt)(uint8_t *, uint32_t);
    int      (*Decrypt)(uint8_t *, uint32_t);
    uint8_t  (*Reset)(void);
    uint32_t (*GetTickCount)(void);
    void     (*Sleep)(uint32_t);
    uint8_t  (*ReadASCIIByte)(void);
    uint16_t (*ReadASCIIWord)(void);
    uint32_t (*ReadASCIIDWord)(void);
    void     (*WriteASCIIByte)(uint8_t);
    void     (*WriteASCIIWord)(uint16_t);
    void     (*WriteASCIIDWord)(uint32_t);
    void     (*PutChar)(uint8_t);
    uint8_t  (*GetChar)(void);
    uint8_t  (*WaitChar)(uint8_t *, uint32_t);
    uint8_t  (*IsOpen)(void);
 BootFunctionTable_t;

然后我使用 default_function_attribute pragma 声明该类型的变量,以强制它到特定地址并用我的特定函数填充它。

#pragma default_variable_attributes = @ "boottable"
BootFunctionTable_t bootFunctions =

        MAJOR_REVISION,
        MINOR_REVISION,
        BootSerialInit,     /* Communication Init */
        BootSerialDeInit,   /* Communication Deinit */
        BootSerialWrite,
        BootSerialRead,
        BootSerialAttached,
        BootExitToApp,
        BootJump,
        BootGetCRC,
        NULL,
        NULL,
        BootReset,
        BootGetTickCount,
        BootSleep,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        BootSerialPutChar,
        BootSerialGetChar,
        NULL
;
#pragma default_variable_attributes =

在 main 中,我创建了一个新指针并将其指向我试图强制该表的地址

BootFunctionTable_t * bootf;
bootf = (BootFunctionTable_t *)0x080000200;

最后,我在链接器文件中创建该部分

/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/

define symbol __ICFEDIT_intvec_start__ =    0x08000000;

/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__    = 0x08000300;
define symbol __ICFEDIT_region_ROM_end__      = 0x080FFFFF;
define symbol __ICFEDIT_region_RAM_start__    = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__      = 0x2001FFFF;
define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_CCMRAM_end__   = 0x1000FFFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__   = 0x200;
/**** End of ICF editor section. ###ICF###*/


define memory mem with size = 4G;
define region ROM_region        = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
define region RAM_region        = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
define region CCMRAM_region     = mem:[from __ICFEDIT_region_CCMRAM_start__   to __ICFEDIT_region_CCMRAM_end__];
define region BOOTTABLE_region  = mem:[from 0x08000200 to 0x080002FF];

initialize by copy section boottable;
place in BOOTTABLE_region  readonly section boottable;

define block CSTACK    with alignment = 8, size = __ICFEDIT_size_cstack__    ;
define block HEAP      with alignment = 8, size = __ICFEDIT_size_heap__      ;

initialize by copy  readwrite ;
do not initialize   section .noinit ;

place at address mem:__ICFEDIT_intvec_start__  readonly section .intvec ;


place in ROM_region    readonly ;
place in RAM_region    readwrite,
                        block CSTACK, block HEAP ;

但我不能让链接器将 bootFunctions 放在请求的地址。有人可以告诉我我做错了什么吗?我什至无法让该部分显示在地图文件中。我能找到的唯一示例是 .intvec 部分,但向量表是在程序集文件中定义的。我想将我的引导表放在 C 文件中。

【问题讨论】:

我猜#pragma default_variable_attributes = @ "boottable" 会为您创建该部分。您需要将该部分放入一个区域中。如果您的代码编译正确,您应该会在地图中看到该符号,但将其放置在默认部分。 我在链接描述文件中创建了上面发布的部分。 default_variable_attributes 刚刚放在我已经创建的部分。 from 0x08000200 to 0x000002FF 不是有效范围。 感谢@ElderBug,不幸的是这并不能解决它。有一次我做对了,但是当我开始四处移动它试图看看我是否试图把它贴在一个禁止的位置时,我把它搞砸了。我已经编辑了原始帖子以修复它。 【参考方案1】:

链接器会排除未使用的符号。

尝试明确告诉链接器保留该部分。添加如下一行:

keep  section boottable ;

【讨论】:

【参考方案2】:

@user694733 是正确的。因为我实际上并没有使用

BootFunctionTable_t bootFunctions

而是链接器将其遗漏的硬编码地址。我将代码更改为

BootFunctionTable_t * bootf;
bootf = &bootFunctions;

这也解决了它。

【讨论】:

【参考方案3】:

我不得不说我无法让“保持”链接器指令为我工作。我确实找到了 IAR 注释 51348 https://www.iar.com/support/tech-notes/linker/the-linker-removing-functions-and-variables-or-external-not-found/,它建议使用 __root 强制链接器保留内容,这对我有用。

【讨论】:

以上是关于无法使用 IAR ARM 编译器将函数表强制到特定地址的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ARM 的 IAR 编译器编译 Google Test

如何在 IAR 编译器的特定位置放置变量或函数?

如何强制 IAR 使用所需的 Cortex-M0+ 指令(此功能将禁用优化。)

IAR for ARM编译器使用技巧之一

ARM 编译工具keil 和 IAR 命令行编译和下载

stm32项目到IAR