Question

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
Was it helpful?

Solution

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.

OTHER TIPS

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) $< -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/$@

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

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];
}

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  

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)

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top