AVR链接器错误,"重定位被截断以适应"

Far*_*arK 8 linker avr arduino linker-errors avr-gcc

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

..."重定位被截断以适合:R_AVR_13_PCREL对象"......"avr5/libgcc.a"......

通过谷歌发现这是一个常见的错误,但没有任何解决方案对我有用.我唯一不能做的是在链接器句子的末尾加上"-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)
Run Code Online (Sandbox Code Playgroud)

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 ""
Run Code Online (Sandbox Code Playgroud)

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
        )
Run Code Online (Sandbox Code Playgroud)

Makefile文件

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
Run Code Online (Sandbox Code Playgroud)

Jim*_*myB 11

说明:

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

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

AVR设备支持两种跳转/呼叫指令:JMPvs RJMP.和CALLvs RCALL..这些R变体对于当前位置进行调用,并且在程序存储器的使用和执行时间方面都更有效.这需要付出代价:RJMP并且RCALL只能用于程序存储器中位置+/- 4kb范围内的地址.这对于程序存储器不超过8kb的设备来说绝不是问题,因为整个8kb范围可以通过RCALL或从任何位置寻址RJMP.

但是,在程序存储器超过8kb的设备上,并非所有可能的位置都是如此.因此,如果连接器决定它可以把被称为代码从该+/- 4KB范围RJMP/ RCALL不会有问题,如果链接失败(重新)找到代码是该范围内,RJMP/ RCALL 不能用于到达代码的新地址,因此地址被截断(就像uint16_t value = 12345; uint8_t truncatedValue = value;在C中一样)并且生成的代码中断.

请注意,对于超过4kb程序存储器的任何给定项目(在程序存储器大于8kb的设备上),这可能会可能不会发生,因为它取决于所需代码的重定位,这可能基本上随每个新行的添加或删除C代码,添加每个库以进行链接,甚至链接库或其他代码片段的顺序(例如,当链接器找到代码时,从"A"到"B"调用可能有效比如"AB C",但是当链接器决定像"AC B"那样重新定位时失败.

解:

您必须让编译器知道它需要生成JMP/ CALL指令而不是(更有效)RJMP/ RCALL指令.在AVR Studio/Atmel Studio中,可以在项目的属性,工具链,AVR/GNU C编译器,优化中完成.相关选项是"在> 8k设备上使用rjmp/rcall(有限范围)(-mshort-calls)",需要取消选中该命令以防止指定错误.
如标签所示,当从IDE外部调用gcc时-mshort-calls,需要从gcc命令行参数列表中删除相关的命令行选项以实现相同的操作.

更新:

为了避免不必要的混淆这种错误可能造成-mshort-calls在AVR-GCC 4.7弃用并会从4.8被移除.资料来源:GCC 4.8变动.

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