链接失败并显示 "relocation truncated to fit" 具有积极的内联

Linking fails with "relocation truncated to fit" with aggressive inlining

为了解决 a Rust compiler bug in the AVR backend,我将我的很多函数标记为 #[inline(always)],只需添加注释,直到足够的案例优化等会触发我不再运行 进入问题。

但是,有了这些注释,链接现在会失败并显示大量 relocation truncated to fit 消息:

target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_18':
chip8_avr.cgu-0.rs:(.text.main+0x432): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_23':
chip8_avr.cgu-0.rs:(.text.main+0x45c): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_31':
chip8_avr.cgu-0.rs:(.text.main+0x4ae): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_34':
chip8_avr.cgu-0.rs:(.text.main+0x4d2): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_146':
chip8_avr.cgu-0.rs:(.text.main+0x58a): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x58e): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x592): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
target/avr-atmega328p/release/deps/chip8_avr-41c427b8d446a439.o: In function `LBB5_153':
chip8_avr.cgu-0.rs:(.text.main+0x59a): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x59e): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x5a6): relocation truncated to fit: R_AVR_7_PCREL against `no symbol'
chip8_avr.cgu-0.rs:(.text.main+0x5aa): additional relocation overflows omitted from the output
collect2: error: ld returned 1 exit status

This SO answer 意味着大型函数内跳转是编译器需要准备的。 Rust 上的等效设置是什么?

在足够详细地查看反汇编后,发现这些重定位目标都在分支指令的偏移量中,而不是(短)跳转;例如在 0x08:

00000000 <_ZN12chip8_engine7opcodes6decode17haab3c6c935229a6aE>:
   0:   e8 2f           mov     r30, r24
   2:   f9 2f           mov     r31, r25
   4:   80 e0           ldi     r24, 0x00       ; 0
   6:   61 30           cpi     r22, 0x01       ; 1
   8:   01 f4           brne    .+0             ; 0xa <_ZN12chip8_engine7opcodes6decode17haab3c6c935229a6aE+0xa>
   a:   81 83           std     Z+1, r24        ; 0x01
   c:   82 83           std     Z+2, r24        ; 0x02
   e:   81 e0           ldi     r24, 0x01       ; 1

00000010 <LBB0_2>:
  10:   80 83           st      Z, r24
  12:   08 95           ret

Rust 编译器的 AVR 分支当前生成这些具有空 (.+0) 偏移量的分支,然后尝试使用链接器填充它们。对于足够大的函数,这些函数内偏移量可以变成大于适合单个分支指令的内容。

reported this as a compiler bug 在 Rust 的 AVR 分支中。一个可能的解决方案是让链接器在偏移量不合适的情况下生成一个两步分支(一个分支到一个跳转);另一种是根本不使用链接器:由于所讨论的分支是函数内的,因此应该在编译时知道相对地址,以便在需要时生成两步分支。