AVR 链接器错误,“重定位被截断以适合”

发布于 2024-12-17 07:05:34 字数 12391 浏览 0 评论 0原文

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

...“重定位被截断以适合:R_AVR_13_PCREL 符号“...”avr5/libgcc.a“...

我有 通过 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

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) 
lt; -o $(addprefix build/, $(notdir $@)) -lc -lm

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


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

椵侞 2024-12-24 07:05:34

说明:

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

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

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

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

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

解决方案:

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

更新:

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

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

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.

遮云壑 2024-12-24 07:05:34

我已经解决了这个问题,我已经重组了代码(我已经删除了几乎所有全局变量),并且我已经在 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) 
lt; -o $(addprefix build/, $(notdir $@)) $(END_FLAGS)

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


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


# Assemble: create object files from assembler source files.
#.S.o:
#   $(CC) -c $(ALL_ASFLAGS) 
lt; -o build/$@

I've solved the problem, i've restructured code (I've deleted almost all globals variables) and i've added '-lc -lm -lc' flags to makefile. I suppose the problem was the code structure, too many global variables due to bad adaptation from an arduino code style (All source files are pasted into in the same file)
I put the makefile here, I hope it is useful to someone:

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) 
lt; -o $(addprefix build/, $(notdir $@)) $(END_FLAGS)

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


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


# Assemble: create object files from assembler source files.
#.S.o:
#   $(CC) -c $(ALL_ASFLAGS) 
lt; -o build/$@
流星番茄 2024-12-24 07:05:34

过去几个小时我一直在研究这个问题,终于解决了。对我来说,这与 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

I've been working on this problem for the past few hours, and finally solved it. For me it had to do with the fact that the avr libm.a must be included in the linker command, and I was using the Math.h library, which is separate from the libc.a library, and wasn't being linked correctly.

Try modifying the linker command to look like this by adding -lc -lm at the beginning of the command and -lc at the end:

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

My reference:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1290294587

若水般的淡然安静女子 2024-12-24 07:05:34

我遇到了 avr-gcc 重定位截断错误消息并花了一些时间
几天来整理它。简而言之,链接器中似乎存在错误。

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

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

这是发生的事情。 Flash存储器的前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];
}

I ran into the avr-gcc relocation truncation error message and spent a couple
of days sorting it out. In short, there appears to be a bug in the linker.

For a quick fix, put this in your code in the global variable area. You
may have to try a few different array sizes.

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

Here's what's going on. The first 224 bytes of flash memory are the interrupt
vector table. When an interrupt occurs (like a timer expires or there's a byte
waiting in some receive buffer), this table tells the processor what code to
execute. This example doesn't use many interrupts, so unused vectors get sent
to the routine bad_interrupt(). Here's a few lines from the vector table.

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>

A few things to notice

  • The bad_interrupt routine is located at address 0x1024
  • The first few vectors use a direct jump to 0x1024
  • The last vectors use a relative jump to 0x1024

The use of both jmp and rjmp is an artifact of the -mrelax compiler flag.
Amongst other things, it tells the compiler to use rjmp instructions
when the destination is close enough (which is +/- 4k). Otherwise,
the compiler should use jmp. This isn't a bad thing, rjmp instructions
run 1 clock faster and use 2 bytes less data.

Without -mrelax, the compiler uses only jmp instructions in the vector
table and the problem goes away. BTW, for our purposes, --relax is
the same as -mrelax.

The problem is that the linker is getting jammed up somehow. In the above
example, when the bad_interrupt routine is located at address 0x1028,
the vector should at address 0x24 should turn into a jmp but the linker
can't do it for some reason. Instead, it leaves the instruction as a
rjmp with a relative offset of +4098. As the allowed range is 4096,
the offset would get truncated to +2, which is a serious error.

The reason why "pad[500] PROGMEM = { 0 };" should work is it will allocate
a chunk of flash memory between the vector table and moves bad_interrupt()
far enough away from the vector table that the linker isn't even tempted
to use a rjmp instruction.

In searching the web, this appears to be a chronic problem with all
sorts of solutions that sometimes work. Popular are using more/less
PSTR("Hello World") constructs and various -lm -lc options. I suspect
these things are just jiggling around subroutine addresses and by blind
luck they fall in places that work.

Below is the code I used to isolate this bug.

//
// 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];
}
岛歌少女 2024-12-24 07:05:34

经过长期斗争,我摆脱了搬迁错误
通过将 -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  

I got rid of relocation errors after a long struggle
by adding -lm -lc to SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "-lm -lc")
so they will be appended at the end by CMke in link.txt
My 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 would look like.

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  
爱要勇敢去追 2024-12-24 07:05:34

我通过 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)

I sorted it out by overring rules at bottom of my 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)
月牙弯弯 2024-12-24 07:05:34

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

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

I had the same problem while using MPLAB X IDE and AVR-Toolchain to compile a short C program for a ATtiny861.
I have used also the params -lc -lm in the linker menu of the project properties and I found it worked with -O0 for no compiler optimization.
A little bit later I thought no optimization is for sure not ideal and I made another try with -O3 - and it worked fine! No relocation error!

Maybe that helps for further examinations. My knowledge about that all is not deeply, so I hope I will not get again this error.

妄想挽回 2024-12-24 07:05:34

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

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

v4.6 版本之前的 avr 工具链发行版存在 libgcc 和 avr-libc 都提供浮点实现的问题。虽然 avr-libc 实现效率更高,但它假设浮点模拟函数位置靠近,因此即使在具有以下功能的设备上,RCALL/RCALL 也可以访问其他浮点函数:闪存大小大于 8 KiB。但是,无法保证此类浮点函数紧密相连,因此 avr-libc 做出了 错误的假设 这可能会导致 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

If __addsf3 is not found then everything is Fine 。如果找到了,您可能会摆脱-lm的摆弄。 是工具链分发的位置, 是您的 GCC 版本。

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

建议添加 -mshort -calls 已经过时了。今天,-mshort-calls 不是一个优化选项,请参阅 v8 发行说明

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

其效果是代码大小更小,从而降低了重定位截断以适合问题的概率。可以通过-mrelax来实现预期效果,或者,如果您的版本尚不支持,则可以使用-Wl,--relax

Adding -lm is no more needed in recent avr-gcc

Adding -lm as proposed in the other answers is not the proper solution for recent version of avr-gcc (v4.7.2 released 2012 and newer).

The avr toolchain distributions up to versions v4.6 had the problem that both libgcc and avr-libc were providing float implementations. Whilst the avr-libc implementation is much more efficient, it assumed that the float emulation functions are located close together so that RCALL/RCALL could reach other float functions even on devices with flash sizes greater than 8 KiB. However, there is no guarantee whatsoever that such float functions are located close together, hence avr-libc made wrong assumptions that might lead to situations where RJMP/RCALL could not reach their targets (encoded as relocation R_AVR_13_PCREL).

The problem was made worse by linking inefficient float code from libgcc (which was not actually needed because such functions were also supplied by avr-libc). That was fixed in v4.7.2: Respective functions are excluded from libgcc since then, and -lm is automatically added to the linker options, see PR54461. You can see this when compiling and linking with, for example avr-gcc simple.c -Wl,-v -mmcu=atmega8. The options that avr-gcc passes down to the linker read:

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

which means -lm is already in the correct place and you can reference libgcc functions from libm and libc and vice versa.

Whether or not your libgcc comes with float functions that are supposed to be provided by avr-libc can be detected by the following command:

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

If __addsf3 is not found then everything is fine. If it is found, you might get away with -lm fiddling. <INSTALL> is the location of your toolchain distribution, and <VERSION> is your GCC version.

-mshort-calls is NOT an optimization option in v8+

Recommendation of adding -mshort-calls is outdated. Today, -mshort-calls is NOT an optimization option, see v8 release notes:

• A new command-line option -mshort-calls is supported. This option is used internally for multilib selection of the avrxmega3 variants. It is not an optimization option. Do not set it by hand.

Its effect was that code size was smaller, which reduced the probability of the relocation-truncated-to-fit problem. The intended effect can be achieved by -mrelax, or, if your version does not support that yet, then -Wl,--relax.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文