【问题标题】:AVR linker error, "relocation truncated to fit"AVR 链接器错误,“重定位被截断以适应”
【发布时间】:2012-01-01 14:18:58
【问题描述】:

我正在尝试为 ATmega328 micro 编译一些代码,我想使用 Arduino 的库和核心。我正在使用CMake。我已经编译了核心库和我的代码的所有对象以及 Arduino 的库。但是当它链接时,他们向我显示以下错误。

..."重定位被截断以适应:R_AVR_13_PCREL 针对 符号"..."avr5/libgcc.a"...

我有 found through Google 这是一个常见错误,但没有任何解决方案对我有用。我唯一不能做的就是在链接器语句的末尾加上“-lm”和“-lc”标志,因为我不知道如何使用 CMake 来做到这一点。

编辑:我也尝试过使用 makefile 编译它,但我得到了相同的结果,甚至在链接器语句的末尾添加了“-lm”和“-lc”标志。

我把我的 Makefile 和 CMake 文件放在这里:


CMakeList.txt CMake 主文件

cmake_minimum_required(VERSION 2.6)
Project(IMU)

set(ARDUINO_PROCESSOR atmega328p)
set(ARDUINO_PROCESSOR_FREQ 1600000L)

include(./arduino.cmake)

add_library(ardlib
        libraries/EEPROM/EEPROM.cpp
        libraries/Wire/utility/twi.c
        libraries/Wire/Wire.cpp
        libraries/HMC58X3/HMC58X3
        )

LINK_DIRECTORIES(${IMU_SRC_DIR}/libarduinocore
        ${IMU_SRC_DIR}/libraries/EEPROM
        ${IMU_SRC_DIR}/libraries/Wire
        ${IMU_SRC_DIR}/libraries/HMC58X3
        )

link_libraries(arduinocore ardlib)

include_directories(
        libarduinocore
        libraries/EEPROM
        libraries/Wire
        libraries/Wire/utility
        libraries/HMC58X3
        )

set(C_SRCS
        ADXL345.cpp
        ApplicationRoutines.cpp
        DCM.cpp
        HMC5883L.cpp
        ITG3200.cpp
        matrix.cpp
        output.cpp
        timing.cpp
        vector.cpp
        )

set(C_HDRS
        ADXL345.h
        ApplicationRoutines.h
        DCM.h
        HMC5883L.h
        ITG3200.h
        matrix.h
        output.h
        timing.h
        vector.h
        declarations.h
        )

add_executable(IMU.elf main.cpp ${C_SRCS} ${C_HDRS})

add_subdirectory(libarduinocore)

arduino.cmake。即由 CMakeList.txt 导入:

set(ARDUINO_PROCESSOR atmega328p)
set(ARDUINO_PROCESSOR_FREQ 16000000L)

# This module defines macros intended for use by cross-compiling toolchain files when
# CMake is not able to automatically detect the compiler identification.
include (CMakeForceCompiler)

# Set this for cross compiling.  Otherwise it is set to CMAKE_HOST_SYSTEM_NAME,
# which is the system we are developing on.
set (CMAKE_SYSTEM_NAME Generic)

# It sets CMAKE_<lang>_COMPILER to the given compiler and the cmake internal variable
# CMAKE_<lang>_COMPILER_ID to the given compiler-id. It also bypasses the check for
# working compiler and basic compiler information tests.
SET(CMAKE_C_COMPILER avr-gcc)
SET(CMAKE_CXX_COMPILER avr-g++)
cmake_force_cxx_compiler (avr-g++ CrossAVR)
cmake_force_c_compiler (avr-gcc CrossAVR)

# Appparently we want to use the gnuc99 standard.
#set (CSTANDARD "-std=gnu99")

# Generate .stabs debugging symbols for assembler source lines. This enables avr-gdb to
# trace through assembler source files.
#set (CDEBUG "-gstabs")

# Warn for functions declared or defined without specified argument types.
set (CWARN "-Wall -Wstrict-prototypes")

# -funsigned-char - Make any unqualfied char type an unsigned char. Without this option,
#   they default to a signed char.
# -funsigned-bitfields - Make any unqualified bitfield type unsigned. By default,
#    they are signed.
# -fpack-struct - Pack all structure members together without holes.
# -fshort-enums - Allocate to an enum type only as many bytes as it needs for the declared
#   range of possible values. Specifically, the enum type will be equivalent to the
#   smallest integer type which has enough room.
set (CTUNING_FLAGS "-ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums")

# Optimize for size.   The special option -Os is meant to turn on all -O2 optimizations
# that are not expected to increase code size.
set (COPT "-Os")

SET(CINCS "-I${ArduinoCode_SOURCE_DIR}/libarduinocore")

# Finally the compilation flags are now configured.
set(CMAKE_CXX_FLAGS "-lc -lm -mmcu=${ARDUINO_PROCESSOR} -DF_CPU=${ARDUINO_PROCESSOR_FREQ} ${CTUNING_FLAGS} ${CWARN} ${CSTANDARD} ${CDEBUG} ${COPT} ${CINCS} -lc")
set(CMAKE_C_FLAGS "-lc -lm ${CMAKE_CXX_FLAGS} ${CTUNING_FLAGS} ${CWARN} ${CSTANDARD} ${CDEBUG} ${CINCS} -lc")

# On gentoo, -rdynamic is passed to the compiler. The avr compiler does not recognize this
# option.  Also, we are not building shared libraries.
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--gc-sections")
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS ""

Arduino 核心 CMake 文件。这是一个放入libarduinocore目录的CMakeList.txt文件。

include(../arduino.cmake)


add_library (arduinocore
        HardwareSerial.cpp
        pins_arduino.c
        Print.cpp
        Tone.cpp
        WInterrupts.c
        wiring_analog.c
        wiring.c
        wiring_digital.c
        wiring_pulse.c
        wiring_shift.c
        WMath.cpp
        WString.cpp
        )

生成文件

TARGET = IMU
PORT = /dev/ttyACM0
BAUD = 57600
PROGRAMMER = arduino
MCU = atmega328p
F_CPU = 8000000L

CXX_SRCS = ADXL345.cpp \
           ApplicationRoutines.cpp \
           DCM.cpp \
           HMC5883L.cpp \
           ITG3200.cpp \
           matrix.cpp \
           output.cpp \
           timing.cpp \
           vector.cpp

CXX_OBJ = $(CXX_SRCS:.cpp=.o)

CXX_HDRS = ADXL345.h \
           ApplicationRoutines.h \
           DCM.h \
           declarations.h \
           HMC5883L.h \
           ITG3200.h \
           matrix.h \
           output.h \
           timing.h \
           vector.h

CORE_DIR = libarduinocore

CORE_CXX_SRCS = $(CORE_DIR)/HardwareSerial.cpp \
                $(CORE_DIR)/Print.cpp \
                $(CORE_DIR)/Tone.cpp \
                $(CORE_DIR)/WMath.cpp \
                $(CORE_DIR)/WString.cpp

CORE_CXX_OBJ = $(CORE_CXX_SRCS:.cpp=.o)                                                                                                                                                                        

CORE_CC_SRCS = $(CORE_DIR)/pins_arduino.c \                                                                                                                                                                    
               $(CORE_DIR)/WInterrupts.c \                                                                                                                                                                     
               $(CORE_DIR)/wiring_analog.c \                                                                                                                                                                   
               $(CORE_DIR)/wiring.c \                                                                                                                                                                          
               $(CORE_DIR)/wiring_digital.c \                                                                                                                                                                  
               $(CORE_DIR)/wiring_pulse.c \                                                                                                                                                                    
               $(CORE_DIR)/wiring_shift.c                                                                                                                                                                      

CORE_CC_OBJ = $(CORE_CC_SRCS:.c=.o)                                                                                                                                                                            

CORE_HDRS = $(CORE_DIR)/binary.h \                                                                                                                                                                             
            $(CORE_DIR)/HardwareSerial.h \                                                                                                                                                                     
            $(CORE_DIR)/pins_arduino.h \                                                                                                                                                                       
            $(CORE_DIR)/Print.h \                                                                                                                                                                              
            $(CORE_DIR)/Stream.h \                                                                                                                                                                             
            $(CORE_DIR)/WCharacter.h \                                                                                                                                                                         
            $(CORE_DIR)/WConstants.h \                                                                                                                                                                         
            $(CORE_DIR)/wiring.h \                                                                                                                                                                             
            $(CORE_DIR)/wiring_private.h \                                                                                                                                                                     
            $(CORE_DIR)/WProgram.h \                                                                                                                                                                           
            $(CORE_DIR)/WString.h

ARD_LIB_DIR = libraries

ARD_LIB_CXX_SRCS = $(ARD_LIB_DIR)/EEPROM/EEPROM.cpp \
                   $(ARD_LIB_DIR)/Wire/Wire.cpp \
                   $(ARD_LIB_DIR)/HMC58X3/HMC58X3.cpp
ARD_LIB_CC_SRCS = $(ARD_LIB_DIR)/Wire/utility/twi.c

ARD_LIB_CXX_OBJ = $(ARD_LIB_CXX_SRCS:.cpp=.o)
ARD_LIB_CC_OBJ = $(ARD_LIB_CC_SRCS:.c=.o)

CC = avr-gcc
CXX = avr-g++
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AR  = avr-ar
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude

ARD_LIB_INC = -I$(ARD_LIB_DIR) -I$(ARD_LIB_DIR)/EEPROM -I$(ARD_LIB_DIR)/Wire -I$(ARD_LIB_DIR)/HMC58X3 -I$(ARD_LIB_DIR)/Wire/utility

FLAGS_WARN = -Wall -Wstrict-prototypes
FLAGS_TUNING = -ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
FLAGS_OPT = -Os

ALL_INC = -I. $(ARD_LIB_INC) -I$(CORE_DIR)
OBJS = $(CXX_OBJ) $(CORE_CXX_OBJ) $(CORE_CC_OBJ) $(ARD_LIB_CC_OBJ) $(ARD_LIB_CXX_OBJ)
ALL_OBJS := $(addprefix build/, $(notdir $(OBJS)))
ALL_CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) $(ALL_INC) $(FLAGS_WARN) $(FLAGS_TUNNIG) $(FLAGS_OPT)
ALL_CXXFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) $(ALL_INC) -Wall $(FLAGS_TUNNIG) $(FLAGS_OPT)
#ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)

all : $(TARGET).hex
        avr-objcopy -O ihex -R .eeprom $(TARGET).out $(TARGET).hex

$(TARGET).out : $(OBJS)
        $(CXX) $(ALL_CXXFLAGS) main.cpp $(ALL_OBJS) -o $(TARGET).out -lc -lm

upload : $(TARGET).hex
        avrdude -c$(PROGRAMMER) -p$(MCU) -P$(PORT) -U flash:w:$(TARGET).hex

serialmon :
        picocom -b$(BAUD) $(PORT)

.SUFFIXES: .hex .cpp .o .c

# Compile: create object files from C++ source files.
.cpp.o:
        $(CXX) -c $(ALL_CXXFLAGS) $< -o $(addprefix build/, $(notdir $@)) -lc -lm

# Compile: create object files from C source files.
.c.o:
        $(CC) -c $(ALL_CFLAGS) $< -o $(addprefix build/, $(notdir $@)) -lc -lm


# Compile: create assembler files from C source files.
.c.s:
        $(CC) -S $(ALL_CFLAGS) $< -o build/$@ -lc -lm

【问题讨论】:

  • 你能显示使用 Makefile 时得到的输出吗?我刚刚遇到了完全相同的问题并通过添加-lm(但没有-lc)来解决它。我只将它添加到 Makefile 中 .elf 目标的行尾。
  • 你确定你不只是内存不足吗? 328p 有高达 32KB 的空间,其中一些空间被引导加载程序使用。

标签: linker arduino linker-errors avr avr-gcc


【解决方案1】:

解释:

正如错误消息所暗示的,问题与 重定位(代码)有关,这会导致发生一些截断。该消息来自链接器,该链接器试图将代码片段映射到程序内存中的适当位置。

当代码被放置或移动到某个位置(“重定位”)并且此代码通过JMPCALL(即函数调用)从另一段代码引用, 重定位地址必须添加到引用它的JMPCALL 指令中。

AVR 设备支持两种 跳转/调用指令:JMPRJMP,以及CALLRCALLR 变体对当前位置进行 relative 调用,并且在使用程序内存和执行时间方面更有效。但这是有代价的:RJMPRCALL 只能用于距它们在程序存储器中的位置 +/-4kb 范围内的地址。这在程序内存不超过 8kb 的设备上绝不是问题,因为整个 8kb 范围都可以通过RCALLRJMP 从任何位置寻址。

但是,在程序内存超过 8kb 的设备上,这对于所有个可能的位置并不适用。因此,if 链接器 决定它可以将要调用的代码RJMP/@987654336 的+/-4kb 范围内@ 不会有问题,但是如果链接器无法(重新)定位到该范围内的代码,RJMP/RCALL不能使用为了到达代码的新地址,该地址被截断(就像在 C 中执行 uint16_t value = 12345; uint8_t truncatedValue = value; 时一样)并且生成的代码中断。

请注意,对于任何超过 4kb 程序内存(在程序内存 >8kb 的设备上)的给定项目,这可能可能不会在某些时候发生,因为它取决于所需代码的重定位,这可能基本上会随着添加或删除的每一行新 C 代码、添加要链接的每个库,甚至是库或其他部分的顺序而改变代码被链接进来(例如,当链接器找到像“ABC”这样的代码时,从“A”调用到“B”可能会起作用,但当链接器决定像“ACB”一样重新定位时会失败)。

解决方案:

您必须让编译器知道它需要生成JMP/CALL 指令而不是(更有效的)RJMP/RCALL 指令。在 AVR Studio/Atmel Studio 中,这可以在项目的属性、工具链、AVR/GNU C 编译器、优化中完成。相关选项是 "Use rjmp/rcall (limited range) on >8k devices (-mshort-calls)" 需要取消选中以防止出现命名错误。 如标签所示,相关的命令行选项是-mshort-calls,需要从 gcc 命令行参数列表中删除,以在从 IDE 外部调用 gcc 时实现相同的效果。

更新:

为避免不必要的混淆,此错误可能导致 -mshort-calls在 avr-gcc 4.7 中已被弃用,并将从 4.8 中删除。来源:GCC 4.8 Changes

用户现在应该使用-mrelax 来生成具有调用优化可能但永远不会产生错误的二进制文件。

【讨论】:

    【解决方案2】:

    我已经解决了这个问题,我已经重组了代码(我已经删除了几乎所有的全局变量)并且我已经在 makefile 中添加了“-lc -lm -lc”标志。我想问题出在代码结构上,由于对 arduino 代码风格的不良适应导致全局变量过多(所有源文件都粘贴到同一个文件中) 我把makefile放在这里,希望对大家有用:

    TARGET = IMU
    PORT = /dev/ttyUSB0
    BAUD_P = 57600
    BAUD_T = 9600
    PROGRAMMER = arduino
    MCU = atmega328p
    F_CPU = 8000000L
    
    CXX_SRCS = ADXL345.cpp \
           ApplicationRoutines.cpp \
           DCM.cpp \
           HMC5883L.cpp \
           ITG3200.cpp \
           output.cpp \
           timing.cpp \
           vector.cpp
    
    CXX_OBJ = $(CXX_SRCS:.cpp=.o)
    
    CXX_HDRS = ADXL345.h \
           ApplicationRoutines.h \
           DCM.h \
           declarations.h \
           HMC5883L.h \
           ITG3200.h \
           output.h \
           timing.h \
           vector.h
    
    CORE_DIR = libarduinocore
    
    CORE_CXX_SRCS = $(CORE_DIR)/HardwareSerial.cpp \
            $(CORE_DIR)/Print.cpp \
            $(CORE_DIR)/Tone.cpp \
            $(CORE_DIR)/WMath.cpp \
            $(CORE_DIR)/WString.cpp
    
    CORE_CXX_OBJ = $(CORE_CXX_SRCS:.cpp=.o)
    
    CORE_CC_SRCS = $(CORE_DIR)/pins_arduino.c \
               $(CORE_DIR)/WInterrupts.c \
               $(CORE_DIR)/wiring_analog.c \
               $(CORE_DIR)/wiring.c \
               $(CORE_DIR)/wiring_digital.c \
               $(CORE_DIR)/wiring_pulse.c \
               $(CORE_DIR)/wiring_shift.c
    
    CORE_CC_OBJ = $(CORE_CC_SRCS:.c=.o)
    
    CORE_HDRS = $(CORE_DIR)/binary.h \
            $(CORE_DIR)/HardwareSerial.h \
            $(CORE_DIR)/pins_arduino.h \
            $(CORE_DIR)/Print.h \
            $(CORE_DIR)/Stream.h \
            $(CORE_DIR)/WCharacter.h \
            $(CORE_DIR)/WConstants.h \
            $(CORE_DIR)/wiring.h \
            $(CORE_DIR)/wiring_private.h \
            $(CORE_DIR)/WProgram.h \
            $(CORE_DIR)/WString.h
    
    ARD_LIB_DIR = libraries
    
    ARD_LIB_CXX_SRCS = $(ARD_LIB_DIR)/EEPROM/EEPROM.cpp \
               $(ARD_LIB_DIR)/Wire/Wire.cpp \
               $(ARD_LIB_DIR)/HMC58X3/HMC58X3.cpp
    ARD_LIB_CC_SRCS = $(ARD_LIB_DIR)/Wire/utility/twi.c
    
    ARD_LIB_CXX_OBJ = $(ARD_LIB_CXX_SRCS:.cpp=.o)
    ARD_LIB_CC_OBJ = $(ARD_LIB_CC_SRCS:.c=.o)
    
    CC = avr-gcc
    CXX = avr-g++
    OBJCOPY = avr-objcopy
    OBJDUMP = avr-objdump
    AR  = avr-ar
    SIZE = avr-size
    NM = avr-nm
    AVRDUDE = avrdude
    
    ARD_LIB_INC = -I$(ARD_LIB_DIR) -I$(ARD_LIB_DIR)/EEPROM -I$(ARD_LIB_DIR)/Wire -I$(ARD_LIB_DIR)/HMC58X3 -I$(ARD_LIB_DIR)/Wire/utility
    
    #FLAGS_WARN = -Wall -Wstrict-prototypes
    #FLAGS_TUNING = -ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
    FLAGS_OPT = -Os
    
    ALL_INC = -I. $(ARD_LIB_INC) -I$(CORE_DIR)
    OBJS = $(CXX_OBJ) $(CORE_CXX_OBJ) $(CORE_CC_OBJ) $(ARD_LIB_CC_OBJ) $(ARD_LIB_CXX_OBJ)
    ALL_OBJS := $(addprefix build/, $(notdir $(OBJS)))
    ALL_CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) $(ALL_INC) $(FLAGS_WARN) $(FLAGS_TUNNIG) $(FLAGS_OPT)
    ALL_CXXFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU) $(ALL_INC) $(FLAGS_TUNNIG) $(FLAGS_OPT) #-Wall
    #ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
    END_FLAGS = -lc -lm -lc
    
    all : $(TARGET).hex
    
    $(TARGET).hex : $(TARGET).out
        avr-objcopy -O ihex -R .eeprom $(TARGET).out $(TARGET).hex
    
    $(TARGET).out : $(OBJS)
        $(CXX) $(ALL_CXXFLAGS) main.cpp $(ALL_OBJS) -o $(TARGET).out $(END_FLAGS)
    
    upload : $(TARGET).hex
        avrdude -c$(PROGRAMMER) -p$(MCU) -b$(BAUD_P) -P$(PORT) -U flash:w:$(TARGET).hex
    
    serialmon :
        picocom -b$(BAUD_T) $(PORT)
    
    .SUFFIXES: .elf .hex .eep .lss .sym .cpp .o .c .s .S
    
    # Define all listing files.
    #LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
    
    # Compile: create object files from C++ source files.
    .cpp.o:
        $(CXX) -c $(ALL_CXXFLAGS) $< -o $(addprefix build/, $(notdir $@)) $(END_FLAGS)
    
    # Compile: create object files from C source files.
    .c.o:
        $(CC) -c $(ALL_CFLAGS) $< -o $(addprefix build/, $(notdir $@)) $(END_FLAGS)
    
    
    # Compile: create assembler files from C source files.
    #.c.s:
    #   $(CC) -S $(ALL_CFLAGS) $< -o build/$@ -lm
    
    
    # Assemble: create object files from assembler source files.
    #.S.o:
    #   $(CC) -c $(ALL_ASFLAGS) $< -o build/$@
    

    【讨论】:

      【解决方案3】:

      过去几个小时我一直在解决这个问题,终于解决了。对我来说,这与 avr libm.a 必须包含在链接器命令中这一事实有关,并且我使用的是 Math.h 库,它与 libc.a 库分开,并且没有正确链接.

      尝试通过在命令开头添加 -lc -lm 并在末尾添加 -lc 来修改链接器命令:

      ${CMD}  -lc -lm ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT}  ${INPUTS}  -lc
      

      我的参考: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1290294587

      【讨论】:

        【解决方案4】:

        我遇到了avr-gcc relocation truncation错误信息,花了几个 天整理出来。简而言之,链接器中似乎存在错误。

        为了快速修复,请将其放入您的代码中的全局变量区域。你 可能需要尝试几种不同的数组大小。

        #include <avr/pgmspace.h>
        const char pad[500] PROGMEM = { 0 };
        

        这就是正在发生的事情。闪存的前 224 字节是中断 向量表。发生中断时(例如计时器到期或有一个字节 在某个接收缓冲区中等待),该表告诉处理器要执行什么代码 执行。这个例子没有使用很多中断,所以发送了未使用的向量 到例程 bad_interrupt()。这是向量表中的几行。

        0000 <__vectors>:
           0:    0c 94 08 08   jmp   0x1010  ; 0x1010 <__ctors_end>
           4:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
           8:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
           c:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          10:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          14:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          18:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          1c:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          20:    0c 94 12 08   jmp   0x1024  ; 0x1024 <__bad_interrupt>
          24:    ff c7         rjmp  .+4094  ; 0x1024 <__bad_interrupt>
          26:    00 00         nop
          28:    fd c7         rjmp  .+4090  ; 0x1024 <__bad_interrupt>
          2a:    00 00         nop
          2c:    fb c7         rjmp  .+4086  ; 0x1024 <__bad_interrupt>
          2e:    00 00         nop
          30:    f9 c7         rjmp  .+4082  ; 0x1024 <__bad_interrupt>
        

        注意事项

        • bad_interrupt 例程位于地址 0x1024
        • 前几个向量使用直接跳转到 0x1024
        • 最后一个向量使用相对跳转到 0x1024

        同时使用 jmp 和 rjmp 是 -mrelax 编译器标志的产物。 除其他外,它告诉编译器使用 rjmp 指令 当目的地足够近时(+/- 4k)。否则, 编译器应该使用 jmp。这不是坏事,rjmp 指令 运行速度快 1 个时钟,使用的数据少 2 个字节。

        没有-mrelax,编译器只使用向量中的jmp指令 表,问题就消失了。顺便说一句,就我们的目的而言, --relax 是 与 -mrelax 相同。

        问题是链接器不知何故被卡住了。在上述 例如,当 bad_interrupt 例程位于地址 0x1028 时, 向量应该在地址 0x24 应该变成一个 jmp 但链接器 由于某种原因不能这样做。相反,它将指令保留为 rjmp 的相对偏移量为 +4098。由于允许的范围是 4096, 偏移量会被截断为 +2,这是一个严重的错误。

        “pad[500] PROGMEM = { 0 };”的原因应该工作是它会分配 向量表和移动之间的一块闪存 bad_interrupt() 离向量表足够远,链接器甚至不会被诱惑 使用 rjmp 指令。

        在搜索网络时,这似乎是所有人的长期问题 有时有效的各种解决方案。流行正在使用更多/更少 PSTR("Hello World") 构造和各种 -lm -lc 选项。我猜测 这些东西只是在子程序地址周围晃来晃去,而且是盲目的 幸运的是,他们落在了有效的地方。

        下面是我用来隔离这个错误的代码。

        //
        // rjmp vector table relocation truncation bug
        //
        // works when the -mrelax option is not used
        //
        //  avr-gcc -g -Wall -mrelax pad.c -mmcu=atmega2560 -Wl,-Map -o pad.elf
        //  avr-objdump -h -S pad.elf > pad.list
        //
        //  avr-gcc --version -> avr-gcc (GCC) 4.7.2
        //
        
        #include <avr/pgmspace.h>
        
        // note, there are other bands of works/fails
        //
        // 3884 works
        // 3886 fails
        // 3894 fails
        // 3896 works
        const char pad[3886] PROGMEM = { 0 };
        
        int main() {
        
          int   i, j;
        
          for (i = 0; 1; i++)
            j += pad[i];
        }
        

        【讨论】:

        【解决方案5】:

        经过长时间的奋斗,我摆脱了搬迁错误 通过将 -lm -lc 添加到 SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-lm -lc") 因此它们将由 CMke 在最后附加在 link.txt 我的 CMakeLists.txt

        # generated by cmkoder 
        PROJECT (ermote1.cmk)
        CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
        SET(CMAKE_SYSTEM_NAME Generic)
        SET(OUT_BINARY_FILE ermote1)
        
        SET(ENV{CROSS_COMPILE} avr-)
        SET(ENV{ARCH} arm)
        SET(ENV{TC_BASE} /home/arduino-1.0.5)
        SET(CROSS_COMPILE avr-)
        SET(ARCH arm)
        SET(TC_BASE /home/arduino-1.0.5)
        SET(TC_SRC_PATH ${TC_BASE}/libraries/)
        
        SET(CMAKE_CXX_COMPILER ${CROSS_COMPILE}c++)
        SET(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc)
        SET(TC_LIB_LINKER ${CROSS_COMPILE}ar)
        SET(TC_GDB ${CROSS_COMPILE}gdb)
        SET(HW_MMCU "-mmcu=atmega328p")
        SET(HW_DF_CPU "-DF_CPU=16000000L")
        SET(HW_VARIANT "eightanaloginputs")
        SET (TC_DEFINES "-DARDUINO=105 -DUSB_VID=null  -DUSB_PID=null")
        SET(CMAKE_CXX_FLAGS "-g -Os -Wall -fno-exceptions -ffunction-sections  -fdata-sections -lm -Wl,-gc-sections ${HW_MMCU} ${HW_DF_CPU} -lc  ${TC_DEFINES}")
        
        SET(CMAKE_C_FLAGS  "${CMAKE_CXX_FLAGS}")
        
        SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-lm -lc")
        
        SET(CMAKE_FIND_ROOT_PATH  ${TC_BASE}/hardware/tools/avr/bin ${TC_BASE}/hardware/tools ${TC_BASE}/hardware/tools/avr/lib/avr/lib)
        
        SET(CMAKE_LIBRARY_PATH  "")
        
        INCLUDE_DIRECTORIES (${TC_BASE}/hardware/arduino/cores/arduino/ 
                             ${TC_BASE}/hardware/arduino/variants/${HW_VARIANT}/ 
                             ${TC_BASE}/libs/ 
                             ${TC_BASE}/libraries/ 
                             ${TC_SRC_PATH}SoftwareSerial 
                             ${TC_SRC_PATH}Wire 
                             ${TC_SRC_PATH}Wire/utility 
                             ${TC_SRC_PATH}Ermote 
                             ${TC_SRC_PATH}Adafruit_BMP085)
        
        SET(TC_SOURCES ${TC_BASE}/hardware/arduino/cores/arduino/HardwareSerial.cpp 
                       ${TC_BASE}/hardware/arduino/cores/arduino/Print.cpp 
                       ${TC_BASE}/hardware/arduino/cores/arduino/WInterrupts.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/wiring_analog.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/wiring.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/wiring_digital.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/wiring_pulse.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/wiring_shift.c 
                       ${TC_BASE}/hardware/arduino/cores/arduino/WMath.cpp 
                       ${TC_BASE}/hardware/arduino/cores/arduino/WString.cpp 
                       ${TC_BASE}/hardware/arduino/cores/arduino/main.cpp 
                       ${TC_BASE}/hardware/arduino/cores/arduino/new.cpp)
        
        
        SET(SDK_SRCS ${TC_SRC_PATH}/SoftwareSerial/SoftwareSerial.cpp 
                     ${TC_SRC_PATH}/Wire/Wire.cpp 
                     ${TC_SRC_PATH}/Wire/utility/twi.c 
                     ${TC_SRC_PATH}/Adafruit_BMP085/Adafruit_BMP085.cpp)
        
        SET(PRJ_SRCS start.cpp)
        
        
        FIND_PROGRAM(AVROBJCOPY "avr-objcopy")
        FIND_PROGRAM(AVRDUDE "avrdude")
        FIND_PROGRAM(AVRSIZE "avr-size")
        
        if(AVROBJCOPY)
            add_custom_target(hex)
            add_dependencies(hex ${OUT_BINARY_FILE})
        
            add_custom_command(TARGET hex POST_BUILD
                COMMAND ${AVROBJCOPY} -O ihex -R .eeprom  ./${OUT_BINARY_FILE} ./${OUT_BINARY_FILE}.hex
            )
            add_custom_target(elf)
            add_dependencies(elf ${OUT_BINARY_FILE})
        
            add_custom_command(TARGET elf POST_BUILD
                COMMAND ${AVROBJCOPY} -O ihex -R .eeprom  ./${OUT_BINARY_FILE} ./${OUT_BINARY_FILE}.elf
            )
            add_custom_target(eep)
            add_dependencies(eep ${OUT_BINARY_FILE})
        
            add_custom_command(TARGET eep POST_BUILD
                COMMAND ${AVROBJCOPY} -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0  ./${OUT_BINARY_FILE} ./${OUT_BINARY_FILE}.eep
            )
        
        endif()
        
        ADD_EXECUTABLE ( ${OUT_BINARY_FILE} ${TC_SOURCES} ${SDK_SRCS} ${PRJ_SRCS})
        

        link.txt 看起来像。

        avr-c++   -g -Os -Wall -fno-exceptions -ffunction-sections  -fdata- 
        sections -lm -Wl,-gc-sections -mmcu=atmega328p -DF_CPU=16000000L -lc  
        -DARDUINO=105 -DUSB_VID=null  -DUSB_PID=null    <all the 
        CMakeFiles/....cpp.o >  -o ermote1 -lm -lc  
        

        【讨论】:

          【解决方案6】:

          我通过覆盖我的 makefile 底部的规则来整理它:

          # (...)
          include /usr/share/arduino/Arduino.mk
          
          LDFLAGS += -lc -lm
          
          $(TARGET_ELF):  $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS)
              $(CC) $(LDFLAGS) -o $@ $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS)
          

          【讨论】:

            【解决方案7】:

            我在使用 MPLAB X IDE 和 AVR-Toolchain 为 ATtiny861 编译一个简短的 C 程序时遇到了同样的问题。 我还在项目属性的链接器菜单中使用了参数 -lc -lm,我发现它与 -O0 一起使用,无需编译器优化。 过了一会儿,我认为没有优化肯定不理想,我再次尝试使用 -O3 - 效果很好!没有重定位错误!

            也许这有助于进一步的检查。我对这一切的了解并不深,所以我希望我不会再犯这个错误。

            【讨论】:

              【解决方案8】:

              在最近的 avr-gcc 中不再需要添加 -lm

              按照其他答案中的建议添加-lm 不是 avr-gcc 最新版本(v4.7.2 2012 年及更新版本)的正确解决方案。

              v4.6 之前的 avr 工具链发行版存在 libgcc 和 avr-libc 都提供浮点实现的问题。虽然 avr-libc 的实现效率更高,但它假设浮点仿真函数位置很近,这样RCALL/RCALL 即使在闪存尺寸更大的设备上也可以访问其他浮点函数更大超过 8 KiB。但是,不能保证这些浮点函数位置很近,因此 avr-libc 生成了wrong assumptions,这可能导致RJMP/RCALL 无法达到其目标的情况(编码为重定位R_AVR_13_PCREL) .

              链接来自 libgcc 的低效浮点代码使问题变得更糟(实际上并不需要,因为此类函数也由 avr-libc 提供)。这在 v4.7.2 中已修复:从那时起,libgcc 中排除了相应的函数,并且-lm自动添加到链接器选项中,请参阅PR54461。您可以在编译和链接时看到这一点,例如avr-gcc simple.c -Wl,-v -mmcu=atmega8。 avr-gcc 传递给链接器的选项如下:

              <path>/ld ... --start-group -lgcc -lm -lc -latmega8 --end-group
              

              这意味着-lm 已经在正确的位置,您可以从 libm 和 libc 引用 libgcc 函数,反之亦然。

              您的 libgcc 是否带有应该由 avr-libc 提供的浮点函数,可以通过以下命令检测:

              avr-objdump -d <INSTALL>/lib/gcc/avr/<VERSION>/libgcc.a | grep __addsf3
              

              如果__addsf3 找不到,那么一切都很好。如果找到它,你可能会摆脱-lm 摆弄。 &lt;INSTALL&gt; 是您的工具链分发的位置,&lt;VERSION&gt; 是您的 GCC 版本。

              -mshort-calls 不是 v8+ 中的优化选项

              添加-mshort-callsRecommendation 已过时。今天,-mshort-calls 不是优化选项,请参阅v8 release notes

              • 支持新的命令行选项-mshort-calls。此选项在内部用于 avrxmega3 变体的 multilib 选择。它不是优化选项。不要手动设置。

              其效果是代码大小更小,从而降低了重新定位截断以适应问题的概率。通过-mrelax可以达到预期的效果,或者,如果你的版本还不支持,那么-Wl,--relax

              【讨论】:

                猜你喜欢
                • 2013-12-25
                • 1970-01-01
                • 2019-05-23
                • 1970-01-01
                • 1970-01-01
                • 2014-08-13
                • 2011-08-29
                • 2016-05-01
                • 2016-04-03
                相关资源
                最近更新 更多