AVR 链接器错误,“重定位被截断以适应" [英] AVR linker error, "relocation truncated to fit"

查看:28
本文介绍了AVR 链接器错误,“重定位被截断以适应"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 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)项目(IMU)设置(ARDUINO_PROCESSOR atmega328p)设置(ARDUINO_PROCESSOR_FREQ 1600000L)包括(./arduino.cmake)add_library(ardlib库/EEPROM/EEPROM.cpp图书馆/电线/实用程序/twi.c图书馆/线/Wire.cpp库/HMC58X3/HMC58X3)LINK_DIRECTORIES(${IMU_SRC_DIR}/libarduinocore${IMU_SRC_DIR}/libraries/EEPROM${IMU_SRC_DIR}/libraries/Wire${IMU_SRC_DIR}/libraries/HMC58X3)链接库(arduinocore ardlib)包含目录(libarduinocore库/EEPROM图书馆/电线图书馆/电线/实用程序库/HMC58X3)设置(C_SRCSADXL345.cpp应用程序.cppDCM文件HMC5883L.cppITG3200.cpp矩阵.cpp输出.cpp定时.cpp向量.cpp)设置(C_HDRSADXL345.h应用程序.hDCM.hHMC5883L.hITG3200.h矩阵.h输出.h时间.h向量.h声明.h)add_executable(IMU.elf main.cpp ${C_SRCS} ${C_HDRS})添加子目录(libarduinocore)

arduino.cmake.这是由 CMakeList.txt 导入的:

set(ARDUINO_PROCESSOR atmega328p)设置(ARDUINO_PROCESSOR_FREQ 16000000L)# 该模块定义了用于交叉编译工具链文件的宏,当# CMake 无法自动检测编译器标识.包括(CMakeForceCompiler)# 为交叉编译设置此项.否则设置为 CMAKE_HOST_SYSTEM_NAME,# 这是我们正在开发的系统.设置(CMAKE_SYSTEM_NAME 通用)# 它将 CMAKE_<lang>_COMPILER 设置为给定的编译器和 cmake 内部变量# CMAKE__COMPILER_ID 到给定的编译器 ID.它还绕过检查# 工作编译器和基本编译器信息测试.设置(CMAKE_C_COMPILER avr-gcc)设置(CMAKE_CXX_COMPILER avr-g++)cmake_force_cxx_compiler (avr-g++ CrossAVR)cmake_force_c_compiler (avr-gcc CrossAVR)# 显然我们想使用 gnuc99 标准.#set (CSTANDARD "-std=gnu99")# 为汇编源代码行生成 .stabs 调试符号.这使 avr-gdb 能够# 跟踪汇编源文件.#set (CDEBUG "-gstabs")# 警告未指定参数类型声明或定义的函数.设置(CWARN-Wall -Wstrict-prototypes")# -funsigned-char - 使任何非限定字符类型成为无符号字符.如果没有这个选项,# 他们默认为带符号的字符.# -funsigned-bitfields - 使任何不合格的位域类型无符号.默认情况下,# 他们签了名.# -fpack-struct - 将所有结构成员打包在一起,没有孔.# -fshort-enums - 分配给枚举类型的字节数与声明所需的字节数相同# 可能值的范围.具体来说,枚举类型将等价于# 有足够空间的最小整数类型.设置(CTUNING_FLAGS-ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums")# 优化大小.特殊选项 -Os 旨在打开所有 -O2 优化# 预计不会增加代码大小.设置(COPT-Os")设置(CINCS-I${ArduinoCode_SOURCE_DIR}/libarduinocore")# 最后编译标志现在被配置.set(CMAKE_CXX_FLAGS "-lc -lm -mmcu=${ARDUINO_PROCESSOR} -DF_CPU=${ARDUINO_PROCESSOR_FREQ} ${CTUNING_FLAGS} ${CWARN} ${CSTANDARD} ${CDEBUG} ${COPT} ${CINCS} -lc")设置(CMAKE_C_FLAGS-lc -lm ${CMAKE_CXX_FLAGS} ${CTUNING_FLAGS} ${CWARN} ${CSTANDARD} ${CDEBUG} ${CINCS} -lc")# 在 gentoo 上,-rdynamic 被传递给编译器.avr 编译器无法识别这一点# 选项.此外,我们不构建共享库.设置(CMAKE_EXE_LINKER_FLAGS-Wl,--gc-sections")设置(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS"

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

include(../arduino.cmake)add_library (arduinocore硬件串行.cpppin_arduino.c打印文件音调文件WInterrupts.c接线模拟.c接线.c连线_digital.c接线脉冲.c接线移位.cWMath.cpp字符串文件)

Makefile

TARGET = IMU端口 =/dev/ttyACM0波特率 = 57600程序员 = arduinoMCU = atmega328pF_CPU = 8000000LCXX_SRCS = ADXL345.cpp \应用程序.cpp \DCM.cpp \HMC5883L.cpp \ITG3200.cpp \矩阵.cpp \输出.cpp \计时.cpp \向量.cppCXX_OBJ = $(CXX_SRCS:.cpp=.o)CXX_HDRS = ADXL345.h \应用程序.h \DCM.h \声明.h \HMC5883L.h \ITG3200.h \矩阵.h \输出.h \计时.h \向量.hCORE_DIR = libarduinocoreCORE_CXX_SRCS = $(CORE_DIR)/HardwareSerial.cpp \$(CORE_DIR)/Print.cpp \$(CORE_DIR)/Tone.cpp \$(CORE_DIR)/WMath.cpp \$(CORE_DIR)/WString.cppCORE_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.cCORE_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.hARD_LIB_DIR = 库ARD_LIB_CXX_SRCS = $(ARD_LIB_DIR)/EEPROM/EEPROM.cpp \$(ARD_LIB_DIR)/Wire/Wire.cpp \$(ARD_LIB_DIR)/HMC58X3/HMC58X3.cppARD_LIB_CC_SRCS = $(ARD_LIB_DIR)/Wire/utility/twi.cARD_LIB_CXX_OBJ = $(ARD_LIB_CXX_SRCS:.cpp=.o)ARD_LIB_CC_OBJ = $(ARD_LIB_CC_SRCS:.c=.o)CC = avr-gccCXX = avr-g++OBJCOPY = avr-objcopyOBJDUMP = avr-objdumpAR = avr-ar尺寸 = avr 尺寸NM = avr-nmAVRDUDE = avrdudeARD_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/utilityFLAGS_WARN = -Wall -Wstrict-prototypesFLAGS_TUNING = -ffunction-sections -fdata-sections -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enumsFLAGS_OPT = -OsALL_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)全部 : $(TARGET).hexavr-objcopy -O ihex -R .eeprom $(TARGET).out $(TARGET).hex$(TARGET).out : $(OBJS)$(CXX) $(ALL_CXXFLAGS) main.cpp $(ALL_OBJS) -o $(TARGET).out -lc -lm上传:$(TARGET).hexavrdude -c$(PROGRAMMER) -p$(MCU) -P$(PORT) -U flash:w:$(TARGET).hex串行监视器:picocom -b$(BAUD) $(PORT).后缀:.hex .cpp .o .c# 编译:从 C++ 源文件创建目标文件..cpp.o:$(CXX) -c $(ALL_CXXFLAGS) $<-o $(addprefix build/, $(notdir $@)) -lc -lm# 编译:从 C 源文件创建目标文件..c.o:$(CC) -c $(ALL_CFLAGS) $<-o $(addprefix build/, $(notdir $@)) -lc -lm# Compile:从 C 源文件创建汇编程序文件..CS:$(CC) -S $(ALL_CFLAGS) $<-o 构建/$@ -lc -lm

解决方案

说明:

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

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

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

在具有超过 8kb 程序存储器的设备上,这并不适用于所有可能的位置.因此,如果链接器决定它可以将要调用的代码放在RJMP的+/-4kb范围内code>/RCALL 不会有问题,但是如果链接器未能(重新)定位到该范围内的代码,RJMP/RCALL 不能用于到达代码的新地址,因此地址被截断(就像在做 uint16_t value =12345; uint8_t truncatedValue = value; in C) 和生成的代码中断.

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

解决方案:

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

更新:

为了避免不必要的混淆,此错误可能会导致 -mshort-calls 在 avr-gcc 4.7 中不推荐使用,并将从 4.8 中删除.来源:GCC 4.8 更改.

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

I'm trying to compile some code for an ATmega328 micro, and I want use the libraries and the core of Arduino. I'm using CMake. I have gotten to compile the core library and all objects of my code and the libraries of Arduino. But when it's linking, they show me the following error.

..."relocation truncated to fit: R_AVR_13_PCREL against symbol"..."avr5/libgcc.a"...

I have found through Google that this is a common error, but no solution has worked for me. The only thing I can't do is put "-lm" and "-lc" flags at the end of the linker sentence, because I don't know how I can do it with CMake.

EDIT: I have tried compile it with makefile too but I have gotten the same result, even putting "-lm" and "-lc" flags at the end of the linker sentence.

I put my Makefile and CMake files here:


CMakeList.txt The main CMake file

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. That is imported by 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 core CMake file. This is a CMakeList.txt file put into libarduinocore directory.

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
        )

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

解决方案

Explanation:

As the error message suggests, the issue has to do with the relocation (of code) which causes some truncation to occur. The message comes from the linker which is trying to map pieces of code to appropriate locations in the program memory.

When code is placed or moved to some location ("relocation") and this code is referred to from another piece of code, via JMP or CALL (i.e. a function call), the relocated address has to be added to the JMP or CALL instruction referring to it.

The AVR devices support two kinds of jump/call instructions: JMP vs. RJMP, and CALL vs. RCALL. The R variants make calls relative to the current location and are more efficient both in usage of program memory and execution time. This comes at a cost though: RJMP and RCALL can only be used for addresses in the range of +/-4kb from their location in program memory. This is never a problem on devices with no more than 8kb of program memory because the whole 8kb range can be addressed from any location via RCALL or RJMP.

On devices with more than 8kb of program memory, however, this is not true for all possible locations. Therefore, if the linker decides it can put the code to be called within the +/-4kb range from the RJMP/RCALL there will be no problem, but if the linker fails to (re-)locate the code to be within that range, RJMP/RCALL cannot be used to reach the code's new address, the address is thus truncated (just like when doing uint16_t value = 12345; uint8_t truncatedValue = value; in C) and the generated code breaks.

Note that this may or may not happen for any given project exceeding 4kb of program memory (on devices with >8kb of program memory) at some point, because it depends on the relocation of code needed, which may basically change with every new line of C code added or removed, with every library added to be linked in, or even the order in which the libraries or other pieces of code are linked in (e.g. calling from "A" to "B" may work when the linker locates the code like "A B C" but fail when the linker decides to relocate like "A C B").

Solution:

You have to let the compiler know that it needs to generate JMP/CALL instructions instead of the (more efficient) RJMP/RCALL instructions. In AVR Studio/Atmel Studio this can be done in the project's properties, toolchain, AVR/GNU C compiler, optimization. The relevant option is "Use rjmp/rcall (limited range) on >8k devices (-mshort-calls)" which needs to be unchecked to prevent the named error.
As the label indicates, the relevant command line option is -mshort-calls which needs to be removed from the gcc command line parameter list to achieve the same when invoking gcc from outside of the IDE.

Update:

To avoid the unnecessary confusion this error may cause -mshort-calls was deprecated in avr-gcc 4.7 and will be removed from 4.8. Source: GCC 4.8 Changes.

Users should now use -mrelax instead to generate binaries that have the call optimizations where possible but will never produce the error.

这篇关于AVR 链接器错误,“重定位被截断以适应"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆