I've got some software compiled to run on an embedded NRF24 target, using a gcc-arm-none-eabi toolchain from here (a custom one that provides gdb with support for python3) . I'm trying essentially, malloc an array from the GDB debugger console at runtime, then fill it with elements that I provide.
I have a pointer defined in a .c file like: static float32_t *array;.
I want to then call a cmd like: call (void*) malloc(num_of_elements*sizeof(float32_t)) from inside the GDB console to allocate an array at runtime, and then fill it with elements with something like maybe: call (void*) memcpy(array, {var1, var2... var n}, n)
My issue is the GDB debugger cannot find the malloc stdlib function. If I do something like:
break malloc
Function "malloc" not defined.
Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal]
It can't find this function, although it is fine with finding <string.h> fns, like memcpy for example and I can't quite work out why this is.
I have a feeling it could be something to do with linking, the program is built with a Makefile, the flags towards the end may be of interest:
LIB_FILES += \
$(SDK_ROOT)/components/toolchain/cmsis/dsp/GCC/libarm_cortexM4lf_math.a \
# Optimization flags
OPT = -O0 -g3
# Uncomment the line below to enable link time optimization
#OPT += -flto
# C flags common to all targets
CFLAGS += $(OPT)
CFLAGS += -DBOARD_PCA10056
CFLAGS += -DARM_MATH_CM4
CFLAGS += -DBSP_DEFINES_ONLY
CFLAGS += -DCONFIG_GPIO_AS_PINRESET
CFLAGS += -DFLOAT_ABI_HARD
CFLAGS += -DNRF52840_XXAA
CFLAGS += -mcpu=cortex-m4
CFLAGS += -mthumb -mabi=aapcs
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# keep every function in a separate section, this allows linker to discard unused ones
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin -fshort-enums
CFLAGS += -DDEV8_PINOUT
CFLAGS += -DNUM_FLASH_BLOCKS=128
CFLAGS += -DDEBUG
CFLAGS += -DNRF_LOG_ENABLED=1
CFLAGS += -DNRF_LOG_BACKEND_UART_ENABLED=1
# C++ flags common to all targets
CXXFLAGS += $(OPT)
# Assembler flags common to all targets
ASMFLAGS += $(OPT)
ASMFLAGS += -mcpu=cortex-m4
ASMFLAGS += -mthumb -mabi=aapcs
ASMFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
ASMFLAGS += -DBOARD_PCA10056
ASMFLAGS += -DBSP_DEFINES_ONLY
ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET
ASMFLAGS += -DFLOAT_ABI_HARD
ASMFLAGS += -DNRF52840_XXAA
ASMFLAGS += -DARM_MATH_CM4
# Linker flags
LDFLAGS += $(OPT)
LDFLAGS += -mthumb -mabi=aapcs -L$(SDK_ROOT)/modules/nrfx/mdk -T$(LINKER_SCRIPT)
LDFLAGS += -mcpu=cortex-m4
LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
# let linker dump unused sections
LDFLAGS += -Wl,--gc-sections
# use newlib in nano version
LDFLAGS += --specs=nano.specs
LDFLAGS += -Wl,--print-memory-usage
nrf52840_xxaa: CFLAGS += -D__HEAP_SIZE=8192
nrf52840_xxaa: CFLAGS += -D__STACK_SIZE=8192
nrf52840_xxaa: ASMFLAGS += -D__HEAP_SIZE=8192
nrf52840_xxaa: ASMFLAGS += -D__STACK_SIZE=8192
# Add standard libraries at the very end of the linker input, after all objects
# that may need symbols provided by these libraries.
LIB_FILES += -lc -lnosys -lm
To debug I'm using GDB with a Jlink server type setup.
Your code needs to explicitly reference the symbol to force it to link, and you need to prevent link optimisation from removing unused references. Rather then doing a dummy call with potential unwanted side effects, you can simply refer to the symbol via a function pointer instantiation thus:
void* (*volatile force_malloc_link)(size_t) = &malloc ;
Or more simply since you will not actually invoke the function through the pointer:
volatile void* force_link_malloc = &malloc ;
You could make it generic with a macro for any symbol you wish to link:
#define FORCE_LINK( sym ) volatile void* force_link_ ## sym = &sym
You can also force the entire library to be linked (if you have the space) - How to force gcc to link an unused static library. One of the answers there explains how you can also unpack the static library and link individual object files.
It can't find this function
The function may not be linked into your binary.
Does your binary call malloc elsewhere?
Do you link against libc.so or libc.a?
Does nm a.out | grep ' malloc' find it?
it is fine with finding <string.h> fns, like memcpy
If your binary calls memcpy and you link against libc.a, then memcpy implementation will be linked in. Using the same nm command from above will show that the memcpy symbol is present and malloc is not.
If you want to call malloc at runtime, you need to make sure it's linked in. One way to achieve this is to add:
const char *argv0;
int main(int argc, char *argv[])
{
argv0 = strdup(argv[0]); // This should guarantee that malloc is linked in.
// rest of the program
}
Related
I am trying to build a simply first blinkyon a nrf51822 china clone (YJ-14015), as part of building a redox wireless and debugging why the BLE communication does not work.
As SDK I use nrf5_SDK_11 as the keyboards custom firmware is based on it.
Now I tried a very minimal example blinky with main.c
#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf_gpio.h"
#define LED_PIN_1 1 // LED connected to pin 1
/* --> from nrf5_SDK_11/components/drivers_nrf/hal/nrf_gpio.h
__STATIC_INLINE void nrf_gpio_pin_set(uint32_t pin_number)
{
NRF_GPIO->OUTSET = (1UL << pin_number);
}
__STATIC_INLINE void nrf_gpio_pin_clear(uint32_t pin_number)
{
NRF_GPIO->OUTCLR = (1UL << pin_number);
}
*/
int main(void)
{
// Make LED pin an output pin
nrf_gpio_cfg_output(LED_PIN_1);
nrf_gpio_pin_set(LED_PIN_1);
// Toggle LEDs.
while (true)
{
// Down
NRF_GPIO->OUTCLR = (NRF_GPIO->OUT & (1UL << LED_PIN_1));
// nrf_gpio_pin_clear(LED_PIN_1);
nrf_delay_ms(1000);
// Up
NRF_GPIO->OUTSET= (NRF_GPIO->OUT | (1UL << LED_PIN_1));
// nrf_gpio_pin_set(LED_PIN_1);
nrf_delay_ms(1000);
}
}
My expectation would have been that I can see the voltage flip every second from high to low to high etc on PIN 01... Unfortunately I only get a 1.55 V vs ground if I attach it to my multi meter, but the voltage just stays constant and nothing changes. Anything I did wrong with this loop?
For flashing I use a ST-LinkV2 clone + the docker containers for openocd and the toolchain of the redox wireless project, which basically uses telnet over openocd. After adjusting for the right paths, flashing seems successful and as mentioned above, PIN 01 can be set to 1.55V, so I assume there is no problem with the flashing itself.
In case someone else stumbles across the same difficulties:
After quite a while, I figured out a way to fix the blinky example for the yj-14015. The key was to adjust the Makefile which I took from the nordic SDK according to the Makefile in the redox firmware.
The relevant lines being as follows:
#flags common to all targets
CFLAGS = -DNRF51
CFLAGS += -DGAZELL_PRESENT
CFLAGS += -DBOARD_CUSTOM
CFLAGS += -DBSP_DEFINES_ONLY
CFLAGS += -mcpu=cortex-m0
CFLAGS += -mthumb -mabi=aapcs --std=gnu99
CFLAGS += -Wall -Werror -O3 -g3
CFLAGS += -Wno-unused-function
CFLAGS += -Wno-unused-variable
CFLAGS += -mfloat-abi=soft
# keep every function in separate section. This will allow linker to dump unused functions
CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums
# Assembler flags
ASMFLAGS += -x assembler-with-cpp
ASMFLAGS += -DNRF51
ASMFLAGS += -DGAZELL_PRESENT
ASMFLAGS += -DBOARD_CUSTOM
ASMFLAGS += -DBSP_DEFINES_ONLY
Here would be the full Makefile.
I kinda liked the idea of having my own sprintf function without the string.h or stdio.h bloatware.
#define sprintf(x) my_sprintf(x)
void my_sprintf(const char * string);
int main(void)
{
sprintf("abc");
}
These are my LD flags:
LDFLAGS += -lgcc
LDFLAGS += --specs=nano.specs
LDFLAGS += -mthumb
LDFLAGS += -mcpu=cortex-m4
# LDFLAGS += --gc-sections
# LDFLAGS += -nostartfiles
# LDFLAGS += -nodefaultlibs
# LDFLAGS += -gc-sections
As you see, I have the nostartfiles and nodefaultlibs options unset. So, even if I had the idea of including string.h or stdio.h, The compiler might find a definition/reference of the sprintf function.
So I'd like to know what if the #define will still refer to the "redefinition" if it is the same than an existing function name.
Any help is warmly welcome.
Yes, but an easier way would be to use a freestanding environment:
gcc -ffreestanding ...
If you want to know if your approach will take effect across files (i.e. #define function(x) y in file1.c and function(z) in file2.c), then no, it won't.
I'm relatively new to makefiles and I have to write a makefile for a large project to compile the project with the gnu gcc compiler.
The relevant header files for the source files are organized in different subdirectories like this:
D:\MyProject\SubProject1\Modules\APP\StateManager\Include
D:\MyProject\Tools\
D:\MyProject\Common\Public
D:\MyProject\Function\Modules\FSW\Public
D:\MyProject\SubProject1\Modules\Version\Include
D:\MyProject\SubProject1\Modules\APP\AC\Include
D:\MyProject\SubProject1\Modules\APP\DBDTmanager\Public
D:\MyProject\SubProject1\Modules\APP\Diag\Include\
D:\MyProject\SubProject1\Modules\APP\FunTTT\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Adc\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Func2\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Stubs\Include
D:\MyProject\SubProject1\Modules\Basis_SW\DTC\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Generated\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Generated_BSM\Include
D:\MyProject\SubProject1\Modules\Basis_SW\Functions\Include
D:\MyProject\SubProject1\Modules\BistTests\Include
D:\MyProject\SubProject1\Modules\BistTests\Include\WatchDog\Include
D:\MyProject\App\ssw\common\Public
D:\MyProject\Bit\Modules\Timer\Include
Any idea how to define the includes in the makefile in a "clearly" and "overseeable" way?
Thx for any suggestions!
Assuming you don't have any other requirements here and just want a fairly clean way of getting all of those entries into your CFLAGS value you could do something like this:
PROJDIR := D:\MyProject
SUBPROJDIR := $(PROJDIR)\SubProject1\Modules
CFLAGS += -I$(PROJDIR)\SubProject1\Modules\APP\StateManager\Include
CFLAGS += -I$(PROJDIR)\Tools\
CFLAGS += -I$(PROJDIR)\Common\Public
CFLAGS += -I$(PROJDIR)\Function\Modules\FSW\Public
CFLAGS += -I$(SUBPROJDIR)\Version\Include
CFLAGS += -I$(SUBPROJDIR)\APP\AC\Include
CFLAGS += -I$(SUBPROJDIR)\APP\DBDTmanager\Public
CFLAGS += -I$(SUBPROJDIR)\APP\Diag\Include\
CFLAGS += -I$(SUBPROJDIR)\APP\FunTTT\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Adc\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Func2\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Stubs\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\DTC\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Generated\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Generated_BSM\Include
CFLAGS += -I$(SUBPROJDIR)\Basis_SW\Functions\Include
CFLAGS += -I$(SUBPROJDIR)\BistTests\Include
CFLAGS += -I$(SUBPROJDIR)\BistTests\Include\WatchDog\Include
CFLAGS += -I$(PROJDIR)\App\ssw\common\Public
CFLAGS += -I$(PROJDIR)\Bit\Modules\Timer\Include
etc.
Use this
INC=-I<header-path-1> -I<header-path-2> -I<header-path3>
PS: they all are seperated by spaces
How to solve the following problem with make?
SRCS1 = a.c b,c
SRCS2 = d.c e.c
SRCS= $(SRCS1) $(SRCS2)
OBJS1 = $(subst .c,.o,$(SRCS1))
OBJS2 = $(subst .c,.o,$(SRCS2))
OBJS = $(OBJS1) $(OBJS2)
include ../Makeconf
(which contains CPPFLAGS=-Dfoo) (the main Makefile is also in ../)
Now I want to compile SRCS1 with foo defined and SRCS2 with foo not defined.
I tried
ifneq (,$(findstring $(OBJS2),$(OBJS)))
CPPFLAGS += -Ufoo
endif
but that adds -Ufoo to all files when compiled. Any ideas?
You haven't shown us enough of the makefile(s) to give a complete answer, but I think this is what you're looking for:
$(OBJS2): CPPFLAGS += -Ufoo
Context :
Trying to understand how lto (link time compilation) works
Code:
I have those files :
julia.h:
#ifndef JULIA_H
#define JULIA_H
#include <stdio.h>
int julian();
#endif // JULIA_H
julia.c :
#include "julia.h"
int julian()
{
printf("Hello Worldu!\n");
return 0;
}
compiled as a shared library like so :
gcc -O3 -fPIC -shared julia.c -o libjulia.so -L$PWD -I$PWD -flto
and my main program :
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "julia.h"
int main()
{
julian();
return 0;
}
compiled with :
gcc -O3 main.c -I/path/to/inc -L/path/to/lib -Wl,-rpath=/path/to/lib -ljulia -flto
It compiles fines.
Question :
So, this is a hello world program but am I doing it right with LTO ?
Is is all it takes to optimize the linkage ?
Thanks
As keltar saied, LTO doesn't affect shared libraries. But...
LTO works with static libraries
Just replace ar by gcc-ar and add the option --plugin gccpath/liblto_plugin.so. This LTO plugin will copy the declarations, types, callgraph and GIMPLE representation from LTO-compiled objects into the static lib. (same for ranlib to be replaced by gcc-ranlib)
In your example
# First retrieve the GCC path
gccpath=$(gcc -print-search-dirs | awk '/install/{print $2}')
# Compile the static library
gcc julia.c -o julia.o -flto -ffat-lto-objects
gcc-ar rcs libjulia.a julia.o --plugin $gccpath/liblto_plugin.so
# Compile & link the executable
gcc main.c libjulia.a -flto -Ofast -march=native
Note: -Ofast introduced in GCC-4.6 [ref] (else use -03)
Update Makefile
GCCPATH = $(shell gcc -print-search-dirs | awk '/install/{print $$2}')
AR = gcc-ar
RANLIB = gcc-ranlib
ARFLAGS += --plugin $(GCCPATH)/liblto_plugin.so
RANLIBFLAGS += --plugin $(GCCPATH)/liblto_plugin.so
CFLAGS += -flto -ffat-lto-objects
CXXFLAGS += -flto -ffat-lto-objects
LDFLAGS += -flto=8 # 8 -> compiles using 8 threads
Do not forget, the real compilation will be done at link time. Therefore, move your optimization flags from CFLAGS (and CXXFLAGS) to LDFLAGS ;-) One more thing, debugging info and LTO is still experimental in GCC-4.9. GCC-5.0 should improve this point...
LTO doesn't affect shared libraries; they're being linked with by dynamic linker, which is not aware of LTO and can't modify code at runtime.
Moreover, LTO doesn't even work with static libraries, but some day it presumably will (it is TODO on gcc wiki).
But yes, what it takes to enable is using -flto on both compilation and linking phases.