Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile linking: undefined reference to _exit

I have been trying to create a neatly-organized makefile project template utilizing the ARM mbed library. I have already solved a few of the problems (see this post) related to header file paths. However, now I am having problems with the linker. My goal is to have sources and headers in src, object files in obj, and the final binaries in either debug or release.

Here is the error I am getting...

make
arm-none-eabi-g++  -DTARGET_M4 -DMBED_BUILD_TIMESTAMP=1453683815.81 -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -DTARGET_RTOS_M4_M7 -DTARGET_FF_MORPHO -DTARGET_CORTEX_M -D__FPU_PRESENT=1 -DTARGET_FF_ARDUINO -DTARGET_STM32F446RE -DTARGET_NUCLEO_F446RE -D__MBED__=1 -DTARGET_STM -DTARGET_STM32F4 -D__CORTEX_M4 -DARM_MATH_CM4 -std=c++98 -fno-rtti -I lib/ -I lib/mbed/ -I lib/mbed/TARGET_NUCLEO_F446RE/ -I lib/mbed/TARGET_NUCLEO_F446RE/TARGET_STM/ -I lib/mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4/ -I lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/ -I lib/mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F446RE/ -o obj/main.o src/main.cc
/usr/lib/gcc/arm-none-eabi/6.1.1/../../../../arm-none-eabi/lib/libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
collect2: error: ld returned 1 exit status
make: *** [makefile:54: obj/main.o] Error 1

This is my makefile. I have denoted where the problem(s) might be, but I am not sure. #Project parameters PROJECT = Nucleo_blink OBJECTS = obj/main.o DEST = debug VPATH = src lib $DEST TARGET = NUCLEO_F446RE

#Compilation options
DEBUG = 1

#Tools
AS      = $(GCC_BIN)arm-none-eabi-as
CC      = $(GCC_BIN)arm-none-eabi-gcc
CXX     = $(GCC_BIN)arm-none-eabi-g++
LD      = $(GCC_BIN)arm-none-eabi-gcc
OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy
OBJDUMP = $(GCC_BIN)arm-none-eabi-objdump
SIZE    = $(GCC_BIN)arm-none-eabi-size 

include $(TARGET).mk

CFLAGS = $(INCLUDE_PATHS) $(CC_SYMBOLS) $(CPU) -c -g -fno-common -fmessage-length=0 -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer -MMD -MP

ifeq ($(HARDFP),1)
        FLOAT_ABI = hard
else
        FLOAT_ABI = softfp
endif

ifeq ($(DEBUG), 1)
        CFLAGS += -DDEBUG -O0
else
        CFLAGS += -DNDEBUG -Os
endif

#MY PROBLEM MAY BE HERE
LD_FLAGS = $(CPU) -Wl,--gc-sections --specs=nano.specs -Wl,--wrap,main -Wl,-Map=$(PROJECT).map,--cref
#`-u _printf_float -u _scanf_float` after -specs for floating point I/O

LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys 

LIBRARIES = -lmbed 

.PHONY: all clean lst size

all: $(PROJECT).bin $(PROJECT).hex

clean:
    rm -f debug/* obj/* asm/* $(DEPS)

obj/%.o: %.c
        $(CC)  $(CC_FLAGS) $(CC_SYMBOLS) -std=c99 $(INCLUDE_PATHS) -o $@ $<

obj/%.o: %.cc
        $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o $@ $<

obj/%.o: %.cpp
        $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o $@ $<

obj/%.o: %.asm
        $(CC) $(CPU) -c -x assembler-with-cpp -o asm/$@ $<

#OR HERE
$(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS)
        $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $(DEST)/$@ $^ $(LIBRARIES) $(LD_SYS_LIBS) $(LIBRARIES) $(LD_SYS_LIBS)

$(PROJECT).bin: $(PROJECT).elf
        $(OBJCOPY) -O binary $< $@

$(PROJECT).hex: $(PROJECT).elf
        @$(OBJCOPY) -O ihex $< $@

$(PROJECT).lst: $(PROJECT).elf
        @$(OBJDUMP) -Sdh $< > $@

lst: $(PROJECT).lst

size: $(PROJECT).elf
        $(SIZE) $(PROJECT).elf

DEPS = $(OBJECTS:.o=.d) $(SYS_OBJECTS:.o=.d)
-include $(DEPS)

Before you ask, I have already tried changing --specs=nano.specs to --specs=nosys.specs. It does nothing. The strange part is that the linker settings above work fine for the automatically generated mbed makefile.

Here is the working makefile. It compiles without errors...

# This file was automagically generated by mbed.org. For more information, 
# see http://mbed.org/handbook/Exporting-to-GCC-ARM-Embedded

GCC_BIN = 
PROJECT = Nucleo_blink
OBJECTS = ./source/main.o 
SYS_OBJECTS = #Long list of object files
INCLUDE_PATHS = -I. -I./source -I./mbed -I./mbed/TARGET_NUCLEO_F446RE -I./mbed/TARGET_NUCLEO_F446RE/TARGET_STM -I./mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4 -I./mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F446RE -I./mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM 
LIBRARY_PATHS = -L./mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM 
LIBRARIES = -lmbed 
LINKER_SCRIPT = ./mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/STM32F446XE.ld

############################################################################### 
AS      = $(GCC_BIN)arm-none-eabi-as
CC      = $(GCC_BIN)arm-none-eabi-gcc
CPP     = $(GCC_BIN)arm-none-eabi-g++
LD      = $(GCC_BIN)arm-none-eabi-gcc
OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy
OBJDUMP = $(GCC_BIN)arm-none-eabi-objdump
SIZE    = $(GCC_BIN)arm-none-eabi-size 

ifeq ($(HARDFP),1)
        FLOAT_ABI = hard
else
        FLOAT_ABI = softfp
endif


CPU = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=$(FLOAT_ABI) 
CC_FLAGS = $(CPU) -c -g -fno-common -fmessage-length=0 -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer -MMD -MP
CC_SYMBOLS = -DTARGET_M4 -DTARGET_FF_ARDUINO -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -DTARGET_RTOS_M4_M7 -DTARGET_FF_MORPHO -DTARGET_LIKE_MBED -DTARGET_CORTEX_M -D__FPU_PRESENT=1 -DTARGET_LIKE_CORTEX_M4 -DTARGET_NUCLEO_F446RE -D__MBED__=1 -DTARGET_STM -DMBED_BUILD_TIMESTAMP=1468213384.59 -DTARGET_STM32F446RE -DTARGET_STM32F4 -D__CORTEX_M4 -DARM_MATH_CM4 

#My makefile above copies these two lines
LD_FLAGS = $(CPU) -Wl,--gc-sections --specs=nano.specs -u _printf_float -u _scanf_float -Wl,--wrap,main -Wl,-Map=$(PROJECT).map,--cref
LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys


ifeq ($(DEBUG), 1)
CC_FLAGS += -DDEBUG -O0
else
CC_FLAGS += -DNDEBUG -Os
endif

.PHONY: all clean lst size

all: $(PROJECT).bin $(PROJECT).hex size


clean:
        rm -f $(PROJECT).bin $(PROJECT).elf $(PROJECT).hex $(PROJECT).map $(PROJECT).lst $(OBJECTS) $(DEPS)


.asm.o:
        $(CC) $(CPU) -c -x assembler-with-cpp -o $@ $<
.s.o:
        $(CC) $(CPU) -c -x assembler-with-cpp -o $@ $<
.S.o:
        $(CC) $(CPU) -c -x assembler-with-cpp -o $@ $<

.c.o:
        $(CC)  $(CC_FLAGS) $(CC_SYMBOLS) -std=gnu99   $(INCLUDE_PATHS) -o $@ $<

.cpp.o:
        $(CPP) $(CC_FLAGS) $(CC_SYMBOLS) -std=gnu++98 -fno-rtti $(INCLUDE_PATHS) -o $@ $<



$(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS)
        $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $@ $^ -Wl,--start-group $(LIBRARIES) $(LD_SYS_LIBS) -Wl,--end-group


$(PROJECT).bin: $(PROJECT).elf
        $(OBJCOPY) -O binary $< $@

$(PROJECT).hex: $(PROJECT).elf
        @$(OBJCOPY) -O ihex $< $@

$(PROJECT).lst: $(PROJECT).elf
        @$(OBJDUMP) -Sdh $< > $@

lst: $(PROJECT).lst

size: $(PROJECT).elf
        $(SIZE) $(PROJECT).elf

DEPS = $(OBJECTS:.o=.d) $(SYS_OBJECTS:.o=.d)
-include $(DEPS)

I think my problem is some sort of path error... - The _exit symbol may be defined, but inaccessible by main.o - There may be some major error in the makefile I'm missing - Something totally different?

Feel free to comment any suggested changes to this question.

EDIT: All I had to do to fix the error was change CFLAGS to CCFLAGS. The answer I marked as the solution explained what was happening, and a potential way to fix it. Although I didn't need to use the suggested solution, the explanation of why it wasn't working is useful, and the information provided by both answers is useful.

like image 276
Caleb Reister Avatar asked Jul 11 '16 05:07

Caleb Reister


4 Answers

Adding --specs=nosys.specs to your linker options may also solve this issue.

You can see exactly what this does by looking at the nosys.specs file which will be somewhere in your compiler directory.

See also: exit.c:(.text+0x18): undefined reference to `_exit' when using arm-none-eabi-gcc

like image 129
Tom Avatar answered Nov 20 '22 05:11

Tom


_exit is a system call, as well as some other functions you probably will need later. When you compile a binary for (for example) Linux, these calls are serviced by the operating system. In bare-metal embedded project you need to define these functions by yourself. The common way is to create a file called syscalls.c or something like that and put all needed system calls there. Take a look at example of such file, rapidly found by google: https://github.com/bjornfor/stm32-test/blob/master/STM32L1xx_StdPeriph_Lib_V1.1.1/syscalls.c

As a bonus, if you properly implement _read and _write to work with UART, you will get a serial console capable to do formatted IO via printf and scanf .

like image 44
Sergey Avatar answered Nov 20 '22 05:11

Sergey


The _exit symbol may be defined, but inaccessible by main.o - There may be some major error in the makefile I'm missing - Something totally different?

This happens when a call to a standard library method indirectly has a dependency on exit(). Often from automatically generated exception unwind code that's supposed to abort your process on exit, which obviously has different semantics in a bare metal application. The division-by-zero floating point exception is one such example. -fno-exceptions does not help with this.

You can of course supply a do-nothing exit() handler but your code would be smaller if the exception unwind code didn't get inserted in the first place.

I discovered by examining the generated assembler that you can replace the exception handlers with do-nothing versions like this in a compilation unit:

extern "C" void __wrap___aeabi_unwind_cpp_pr0() {} 
extern "C" void __wrap___aeabi_unwind_cpp_pr1() {} 
extern "C" void __wrap___aeabi_unwind_cpp_pr2() {} 

and then link those in as replacements at link time with these additional linker arguments.

-Wl,-wrap,__aeabi_unwind_cpp_pr0,
-Wl,-wrap,__aeabi_unwind_cpp_pr1
-Wl,-wrap,__aeabi_unwind_cpp_pr2

Another benefit is that your code should shrink as a result. You may even want to insert your own implementations that reset the MCU.

like image 3
Andy Brown Avatar answered Nov 20 '22 05:11

Andy Brown


For me it took both -fno-exceptions and --specs=nosys.specs in compiler flags.

like image 1
Tarak Patel Avatar answered Nov 20 '22 07:11

Tarak Patel