This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430-GCC-opensource:可能的编译器错误:调用者保存的寄存器不会在间接调用中保存

Guru**** 2989100 points

Other Parts Discussed in Thread: MSP430F249

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1665398/msp430-gcc-opensource-possible-compiler-bug-caller-saved-register-is-not-saved-across-indirect-call

器件型号: MSP430-GCC-OPENSOURCE
主题中讨论的其他器件: MSP430F249

我迭代一个函数指针表、该表使用链接器脚本放置在闪存内。 GCC 使 R12 中的循环/迭代指针保留在间接调用中。 我知道 R12 是调用者保存的寄存器、因此被调用函数如果可以随时缓冲寄存器、调用者应该在整个调用中保留它。

下面是我的应用示例:

typedef void(*sys_init_t)(void);

static void init_fn_0(void) {
    /* trivial, does not disturb r12 */
}

static void init_fn_1(void) {
    volatile int a = 1, b = 2, c = 3, d = 4, e = 5;
    (void)a; (void)b; (void)c; (void)d; (void)e;
    /* enough live locals at -Os to force r12 use as scratch */
}

__attribute__((section(".sys_init"), used))
static const sys_init_t init0 = init_fn_0;

__attribute__((section(".sys_init"), used))
static const sys_init_t init1 = init_fn_1;

extern const sys_init_t __sys_init_start;
extern const sys_init_t __sys_init_end;

void sys_init(void) {
    for(const sys_init_t* fn = &__sys_init_start; fn < &__sys_init_end; fn++) {
        (*fn)();
    }
}

int main() {
    sys_init();
    return 0;
}

除了 Sections 部分之外、我还使用了 MSP430F249 的原始链接器脚本:

.sys_init:
{
_sys_init_start =.;
Keep (*(.sys_init));
_sys_init_end =.;
}> ROM


我将按如下方式构建应用:


msp430-elf-gcc -mcpu=MSP430 -mmcu=msp430f249 -g0 -OS -D__MSP430F249__=1 -c main.c -o main.o
MSP430-elf-gcc -mcpu=MSP430 -mmcu=msp430f249 -g0 -OS -D__MSP430F249__=1 -T linker.ld main.o -o example.out
 
 
sys_init 函数生成的汇编代码如下:
00001148 :
  1148:  3c 40 00 11  mov  #4352、  R12  ;#0x1100

0000114c <.L4>:
  114c:  3c 90 04 11  CMP  #4356、  R12  ;#0x1104
  第 1150 章:我的心        JNC  +4 美元      ;ABS 0x1154
  1152:  30 41.      返回       

00001154 <.L5>:
  1154:  3D 4c      MOV  @R12+,  R13  ;
  1156:  8D 12      呼叫  R13    ;
  1158:  F9 3f      JMP  –12 美元     ;abs 0x114c

可以看到、在 call r13 跳回 0x114c 后、再次对 R12 进行评估、即使被调用的函数可能对寄存器进行了空间控制。 在这种情况下、代码将崩溃。

msp430-elf-gcc -version:

MSP430-elf-gcc (Mitto Systems Limited - MSP430-gcc 9.3.1.11) 9.3.1

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Christian:

    这是 GCC 的 IPA-RA 优化(-FIPA-RA、在-OS 及更高版本上启用)。 GCC 将 init_fn_0 和 init_fn_1 都视为同一 TU 中的静态、确定两者都不是阻塞 R12、并在间接调用中跳过保存它。 这种推理对闭合调用图有效、但对于链接器部分派单是错误的、在这种情况下、其他 TU 可能会提交条目 GCC 从不会看到。

    FIX:添加-fno-IPA-RA 以禁用优化、或者将 sys_init () 移到其自身的转换单元中、使其远离 init_fn_*定义—然后 GCC 将间接调用视为不透明并保守地保存 R12。

    此致、
    Brian