diff --git a/examples/arduino_nano/color/project.xml b/examples/arduino_nano/color/project.xml index 80e6ae2182..367640010f 100644 --- a/examples/arduino_nano/color/project.xml +++ b/examples/arduino_nano/color/project.xml @@ -1,6 +1,7 @@ modm:arduino-nano + diff --git a/examples/black_pill_f411/usbfatfs/project.xml b/examples/black_pill_f411/usbfatfs/project.xml index fe63d5aac3..6e031c66e6 100644 --- a/examples/black_pill_f411/usbfatfs/project.xml +++ b/examples/black_pill_f411/usbfatfs/project.xml @@ -1,6 +1,7 @@ modm:black-pill-f411 + diff --git a/examples/feather_m4/usbserial/project.xml b/examples/feather_m4/usbserial/project.xml index ccf9dc7e8b..59c81d0dea 100644 --- a/examples/feather_m4/usbserial/project.xml +++ b/examples/feather_m4/usbserial/project.xml @@ -2,6 +2,7 @@ modm:feather-m4 + diff --git a/examples/nrf51422-dk/uart_logging/project.xml b/examples/nrf51422-dk/uart_logging/project.xml index 8941401cfd..89712d0ed2 100644 --- a/examples/nrf51422-dk/uart_logging/project.xml +++ b/examples/nrf51422-dk/uart_logging/project.xml @@ -1,6 +1,7 @@ modm:nrf51422-dk + diff --git a/examples/nucleo_f031k6/sk6812/project.xml b/examples/nucleo_f031k6/sk6812/project.xml index 376998bffb..0406462d3b 100644 --- a/examples/nucleo_f031k6/sk6812/project.xml +++ b/examples/nucleo_f031k6/sk6812/project.xml @@ -1,6 +1,7 @@ modm:nucleo-f031k6 + diff --git a/examples/nucleo_f303k8/rtos/project.xml b/examples/nucleo_f303k8/rtos/project.xml index fbd693ec83..3a457bcd09 100644 --- a/examples/nucleo_f303k8/rtos/project.xml +++ b/examples/nucleo_f303k8/rtos/project.xml @@ -1,6 +1,7 @@ modm:nucleo-f303k8 + diff --git a/examples/nucleo_f767zi/ethernet/project.xml b/examples/nucleo_f767zi/ethernet/project.xml index 77967d8985..fb8f0bf341 100755 --- a/examples/nucleo_f767zi/ethernet/project.xml +++ b/examples/nucleo_f767zi/ethernet/project.xml @@ -1,6 +1,7 @@ modm:nucleo-f767zi + diff --git a/examples/nucleo_f767zi/freertos_blink/project.xml b/examples/nucleo_f767zi/freertos_blink/project.xml index 9e8fc1693d..64696497e4 100755 --- a/examples/nucleo_f767zi/freertos_blink/project.xml +++ b/examples/nucleo_f767zi/freertos_blink/project.xml @@ -1,6 +1,7 @@ modm:nucleo-f767zi + diff --git a/examples/nucleo_g071rb/amnb/project.xml b/examples/nucleo_g071rb/amnb/project.xml index f5015b3152..a5ec452bee 100644 --- a/examples/nucleo_g071rb/amnb/project.xml +++ b/examples/nucleo_g071rb/amnb/project.xml @@ -1,6 +1,7 @@ modm:nucleo-g071rb + diff --git a/examples/nucleo_g071rb/apa102/project.xml b/examples/nucleo_g071rb/apa102/project.xml index e2b55a4669..c11babe1ba 100644 --- a/examples/nucleo_g071rb/apa102/project.xml +++ b/examples/nucleo_g071rb/apa102/project.xml @@ -1,6 +1,7 @@ modm:nucleo-g071rb + diff --git a/examples/nucleo_l452re/lvgl/project.xml b/examples/nucleo_l452re/lvgl/project.xml index b238049e4c..6ab002815a 100644 --- a/examples/nucleo_l452re/lvgl/project.xml +++ b/examples/nucleo_l452re/lvgl/project.xml @@ -1,6 +1,7 @@ modm:nucleo-l452re + diff --git a/examples/nucleo_l552ze-q/freertos_blink/project.xml b/examples/nucleo_l552ze-q/freertos_blink/project.xml index 64b4226089..0130908b06 100755 --- a/examples/nucleo_l552ze-q/freertos_blink/project.xml +++ b/examples/nucleo_l552ze-q/freertos_blink/project.xml @@ -1,6 +1,7 @@ modm:nucleo-l552ze-q + diff --git a/examples/samd/usbserial/project.xml b/examples/samd/usbserial/project.xml index 127cc761dc..f7f024e79c 100644 --- a/examples/samd/usbserial/project.xml +++ b/examples/samd/usbserial/project.xml @@ -2,6 +2,7 @@ modm:feather-m0 + diff --git a/examples/weact_u585ci/usb/project.xml b/examples/weact_u585ci/usb/project.xml index c736384e91..01db4ffd0a 100644 --- a/examples/weact_u585ci/usb/project.xml +++ b/examples/weact_u585ci/usb/project.xml @@ -1,6 +1,7 @@ modm:weact-u585ci + diff --git a/ext/aws/modm_port.cpp.in b/ext/aws/modm_port.cpp.in index b56824b4c5..f0709939da 100644 --- a/ext/aws/modm_port.cpp.in +++ b/ext/aws/modm_port.cpp.in @@ -26,13 +26,13 @@ void vApplicationStackOverflowHook(TaskHandle_t /*pxTask*/, char *pcTaskName) // Make the Newlib heap thread-safe with FreeRTOS extern "C" void __malloc_lock(struct _reent *); -void __malloc_lock(struct _reent *) +void modm_used __malloc_lock(struct _reent *) { vTaskSuspendAll(); } extern "C" void __malloc_unlock(struct _reent *); -void __malloc_unlock(struct _reent *) +void modm_used __malloc_unlock(struct _reent *) { xTaskResumeAll(); } diff --git a/ext/rp/pico-sdk b/ext/rp/pico-sdk index fa907dafad..a6f00945e4 160000 --- a/ext/rp/pico-sdk +++ b/ext/rp/pico-sdk @@ -1 +1 @@ -Subproject commit fa907dafad7da1427e2e1c3b10d86b35276f5fab +Subproject commit a6f00945e42d9471c30a54a2fc45e0c0aceb95d8 diff --git a/src/modm/architecture/utils.hpp b/src/modm/architecture/utils.hpp index b13f5872ed..8062dfda74 100644 --- a/src/modm/architecture/utils.hpp +++ b/src/modm/architecture/utils.hpp @@ -146,7 +146,7 @@ #define modm_deprecated(msg) __attribute__((deprecated(msg))) #define modm_likely(x) __builtin_expect(!!(x), 1) #define modm_unlikely(x) __builtin_expect(!!(x), 0) - #define modm_section(s) __attribute__((section(s))) + #define modm_section(s) __attribute__((section(s), used)) #define modm_fallthrough __attribute__((fallthrough)) #define modm_noreturn __attribute__((noreturn)) #define modm_warn_unused_result __attribute__((warn_unused_result)) @@ -159,7 +159,7 @@ // - __attribute__ ((weak, alias ("__aliasedFunction"))) seems to work on Windows # define modm_weak #else - # define modm_weak __attribute__((weak)) + # define modm_weak __attribute__((weak, used)) #endif #if defined(MODM_OS_HOSTED) || defined(MODM_CPU_AVR) diff --git a/src/modm/platform/heap/cortex/heap_block.cpp b/src/modm/platform/heap/cortex/heap_block.cpp index e40bcc03e7..437094176e 100644 --- a/src/modm/platform/heap/cortex/heap_block.cpp +++ b/src/modm/platform/heap/cortex/heap_block.cpp @@ -55,7 +55,7 @@ void __modm_initialize_memory(void) extern void __malloc_lock(struct _reent *); extern void __malloc_unlock(struct _reent *); -void* __wrap__malloc_r(struct _reent *r, size_t size) +void* modm_used __wrap__malloc_r(struct _reent *r, size_t size) { __malloc_lock(r); void *ptr = allocator.allocate(size); @@ -65,14 +65,14 @@ void* __wrap__malloc_r(struct _reent *r, size_t size) return ptr; } -void* __wrap__calloc_r(struct _reent *r, size_t size) +void* modm_used __wrap__calloc_r(struct _reent *r, size_t size) { void *ptr = __wrap__malloc_r(r, size); if (ptr) memset(ptr, 0, size); return ptr; } -void* __wrap__realloc_r(struct _reent *r, void *p, size_t size) +void* modm_used __wrap__realloc_r(struct _reent *r, void *p, size_t size) { if (!p) return __wrap__malloc_r(r, size); // NOT IMPLEMENTED! @@ -80,7 +80,7 @@ void* __wrap__realloc_r(struct _reent *r, void *p, size_t size) return NULL; } -void __wrap__free_r(struct _reent *r, void *p) +void modm_used __wrap__free_r(struct _reent *r, void *p) { __malloc_lock(r); allocator.free(p); diff --git a/src/modm/platform/heap/cortex/heap_newlib.cpp b/src/modm/platform/heap/cortex/heap_newlib.cpp index 0987802536..7aa53ea175 100644 --- a/src/modm/platform/heap/cortex/heap_newlib.cpp +++ b/src/modm/platform/heap/cortex/heap_newlib.cpp @@ -40,7 +40,7 @@ void __modm_initialize_memory(void) * Note: This implementation is not thread safe (despite taking a * _reent structure as a parameter). */ -void * +void * modm_used _sbrk_r(struct _reent *, ptrdiff_t size) { const uint8_t *const heap = heap_top; diff --git a/src/modm/platform/heap/cortex/heap_tlsf.cpp b/src/modm/platform/heap/cortex/heap_tlsf.cpp index c172542161..eb0b1293a7 100644 --- a/src/modm/platform/heap/cortex/heap_tlsf.cpp +++ b/src/modm/platform/heap/cortex/heap_tlsf.cpp @@ -126,21 +126,21 @@ void * malloc_traits(size_t size, uint32_t traits) return NULL; } -void *__wrap__malloc_r(struct _reent *, size_t size) +void *modm_used __wrap__malloc_r(struct _reent *, size_t size) { // default is accessible by S-Bus and DMA-able return malloc_traits(size, uint32_t(modm::MemoryTrait::AccessSBus) | uint32_t(modm::MemoryTrait::AccessDMA)); } -void *__wrap__calloc_r(struct _reent *r, size_t size) +void *modm_used __wrap__calloc_r(struct _reent *r, size_t size) { void *ptr = __wrap__malloc_r(r, size); if (ptr) memset(ptr, 0, size); return ptr; } -void *__wrap__realloc_r(struct _reent *r, void *p, size_t size) +void *modm_used __wrap__realloc_r(struct _reent *r, void *p, size_t size) { if (!p) return __wrap__malloc_r(r, size); @@ -156,7 +156,7 @@ void *__wrap__realloc_r(struct _reent *r, void *p, size_t size) return ptr; } -void __wrap__free_r(struct _reent *r, void *p) +void modm_used __wrap__free_r(struct _reent *r, void *p) { // do nothing if NULL pointer if (!p) return; diff --git a/src/modm/platform/spi/stm32/spi_master_dma.hpp.in b/src/modm/platform/spi/stm32/spi_master_dma.hpp.in index 7649a24dd6..0ebccc35a6 100644 --- a/src/modm/platform/spi/stm32/spi_master_dma.hpp.in +++ b/src/modm/platform/spi/stm32/spi_master_dma.hpp.in @@ -85,9 +85,9 @@ private: static void handleDmaTransmitComplete(); - static inline bool dmaError { false }; - static inline bool dmaTransmitComplete { false }; - static inline bool dmaReceiveComplete { false }; + static inline volatile bool dmaError { false }; + static inline volatile bool dmaTransmitComplete { false }; + static inline volatile bool dmaReceiveComplete { false }; // needed for transfers where no RX or TX buffers are given static inline uint8_t dmaDummy { 0 }; diff --git a/src/modm/platform/uart/nrf/uart_buffer.hpp b/src/modm/platform/uart/nrf/uart_buffer.hpp index 649b8b5cb3..bb52051434 100644 --- a/src/modm/platform/uart/nrf/uart_buffer.hpp +++ b/src/modm/platform/uart/nrf/uart_buffer.hpp @@ -34,7 +34,7 @@ class BufferedUart, Buffers...>: public BufferedUart txBuffer; static inline uint8_t txBurstBuffer[SIZE]; - static inline std::size_t txBurstLength = 0; + static inline volatile std::size_t txBurstLength = 0; static inline void serviceTxBurst() diff --git a/src/modm/platform/uart/nrfe/uart_buffer.hpp b/src/modm/platform/uart/nrfe/uart_buffer.hpp index 26f337aa0d..399a6c383c 100644 --- a/src/modm/platform/uart/nrfe/uart_buffer.hpp +++ b/src/modm/platform/uart/nrfe/uart_buffer.hpp @@ -34,7 +34,7 @@ class BufferedUart, Buffers...>: public BufferedUart txBuffer; static inline uint8_t dmaTxBuffer[SIZE]; - static inline std::size_t dmaTxLength = 0; + static inline volatile std::size_t dmaTxLength = 0; static inline void serviceDmaTx() diff --git a/src/modm/processing/fiber/context_arm_m.cpp.in b/src/modm/processing/fiber/context_arm_m.cpp.in index 55ac32a74d..254ef6e299 100644 --- a/src/modm/processing/fiber/context_arm_m.cpp.in +++ b/src/modm/processing/fiber/context_arm_m.cpp.in @@ -253,14 +253,14 @@ modm_context_jump(modm_context_t*, modm_context_t*) %# MODM_POP_CONTEXT() - "1: b modm_context_end \n\t" + "1: bl modm_context_end \n\t" %% if not with_psplim :: "i" (StackWatermark) %% endif ); } -void modm_naked +void modm_naked modm_used modm_context_end(uintptr_t) { asm volatile diff --git a/src/modm/processing/fiber/context_avr.cpp b/src/modm/processing/fiber/context_avr.cpp index a31dafe53a..a4b1ed90ec 100644 --- a/src/modm/processing/fiber/context_avr.cpp +++ b/src/modm/processing/fiber/context_avr.cpp @@ -162,7 +162,7 @@ modm_context_start(modm_context_t *to) return modm_context_jump_entry((modm_context_t*)&main_context_sp, to); } -void +void modm_used modm_context_end(uintptr_t retval) { modm_context_jump_return(retval, (modm_context_t*)&main_context_sp); diff --git a/tools/build_script_generator/common.py b/tools/build_script_generator/common.py index 08d5e113a6..c30f483206 100644 --- a/tools/build_script_generator/common.py +++ b/tools/build_script_generator/common.py @@ -290,8 +290,12 @@ def common_compiler_flags(compiler, target): flags["cflags"].append("-g3") flags["cxxflags"].append("-g3") # flags for the linker + flags["linkflags"] = [ + "-ffunction-sections", + "-fdata-sections", + ] if target.identifier["family"] != "darwin": - flags["linkflags"] = [ + flags["linkflags"] += [ "-Wl,--fatal-warnings", "-Wl,--gc-sections", "-Wl,--relax", diff --git a/tools/build_script_generator/make/resources/compiler.mk.in b/tools/build_script_generator/make/resources/compiler.mk.in index 1f86ddd852..895d7ba2c3 100644 --- a/tools/build_script_generator/make/resources/compiler.mk.in +++ b/tools/build_script_generator/make/resources/compiler.mk.in @@ -32,16 +32,15 @@ ASM := $(CC) ifeq ($(C_SUFFIX),) AS := $(C_PREFIX)as - AR := $(C_PREFIX)ar - NM := $(C_PREFIX)nm - RANLIB := $(C_PREFIX)ranlib else AS := $(CXX) - AR := $(C_PREFIX)gcc-ar$(C_SUFFIX) - NM := $(C_PREFIX)gcc-nm$(C_SUFFIX) - RANLIB := $(C_PREFIX)gcc-ranlib$(C_SUFFIX) endif +_probe = $(if $(shell command -v $(1) 2>/dev/null),$(1),$(2)) +AR := $(call _probe,$(C_PREFIX)gcc-ar$(C_SUFFIX),$(C_PREFIX)ar) +NM := $(call _probe,$(C_PREFIX)gcc-nm$(C_SUFFIX),$(C_PREFIX)nm) +RANLIB := $(call _probe,$(C_PREFIX)gcc-ranlib$(C_SUFFIX),$(C_PREFIX)ranlib) + OBJCOPY := $(C_PREFIX)objcopy OBJDUMP := $(C_PREFIX)objdump SIZE := $(C_PREFIX)size diff --git a/tools/build_script_generator/module.lb b/tools/build_script_generator/module.lb index 34644ec938..edbc5b98b7 100644 --- a/tools/build_script_generator/module.lb +++ b/tools/build_script_generator/module.lb @@ -74,6 +74,9 @@ def prepare(module, options): module.add_option( BooleanOption(name="info.build", default=False, description=descr_info_build)) + module.add_option( + BooleanOption(name="lto", default=False, + description=descr_lto)) if platform in ["avr"]: module.add_option( @@ -186,6 +189,10 @@ def build(env): for flag, values in common_compiler_flags("gcc", env[":target"]).items(): env.collect(flag, *values) + if env["lto"]: + env.collect(":build:ccflags", "-flto=auto") + env.collect(":build:linkflags", "-flto=auto") + # Copy python tools folder platform = env[":target"].identifier["platform"] is_cortex_m = env[":target"].has_driver("core:cortex-m*") @@ -301,6 +308,20 @@ descr_info_git = """# Generate git repository state information descr_info_build = """# Generate build state information""" +descr_lto = """# Enable Link-Time Optimization + +Compiles with `-flto=auto`, which defers code generation to link time so that +the optimizer can inline and eliminate code across translation units. This +typically shrinks the binary noticeably at the cost of a slower link step. + +!!! warning "LTO cannot see references from the linkerscript or inline assembly" + The optimizer decides what is reachable *before* the linkerscript is + applied, so `KEEP()` does not protect a symbol from being deleted. Anything + that is only referenced by the hardware (like the vector table), by the + linkerscript, or from an inline assembly string must be marked `modm_used`. + modm does this for its own symbols. +""" + descr_openocd_cfg = """# Path to a custom OpenOCD configuration file If you have a custom configuration file for your target, it will get included diff --git a/tools/build_script_generator/scons/site_tools/gcc_retarget.py b/tools/build_script_generator/scons/site_tools/gcc_retarget.py index 7b101f4898..808772f5de 100644 --- a/tools/build_script_generator/scons/site_tools/gcc_retarget.py +++ b/tools/build_script_generator/scons/site_tools/gcc_retarget.py @@ -50,15 +50,12 @@ def generate(env, **kw): env['CXX'] = prefix + 'g++' + suffix env['AR'] = prefix + 'ar' env['RANLIB'] = prefix + 'ranlib' - if suffix == '': - env['AS'] = prefix + 'as' - env['NM'] = prefix + 'nm' - else: - env['AS'] = prefix + 'gcc' + suffix - env['NM'] = prefix + 'gcc-nm' + suffix - if sys.platform != "darwin": - env['AR'] = prefix + 'gcc-ar' + suffix - env['RANLIB'] = prefix + 'gcc-ranlib' + suffix + env['AS'] = prefix + 'as' if suffix == '' else prefix + 'gcc' + suffix + + env['NM'] = prefix + 'nm' + for var, wrapper in [('AR', 'gcc-ar'), ('RANLIB', 'gcc-ranlib'), ('NM', 'gcc-nm')]: + if shutil.which(prefix + wrapper + suffix) is not None: + env[var] = prefix + wrapper + suffix env['OBJCOPY'] = prefix + 'objcopy' env['OBJDUMP'] = prefix + 'objdump' diff --git a/tools/modm_tools/size.py b/tools/modm_tools/size.py index a052e3ea4b..a979d19726 100644 --- a/tools/modm_tools/size.py +++ b/tools/modm_tools/size.py @@ -76,6 +76,15 @@ def format(source, device_memories): else: memories["rom"].append(memory) + for name, mems in list(memories.items()): + merged = [] + for memory in sorted(mems, key=lambda m: m["start"]): + if merged and (merged[-1]["start"] + merged[-1]["size"] == memory["start"]): + merged[-1]["size"] += memory["size"] + else: + merged.append(dict(memory)) + memories[name] = merged + memory_sections = [] with open(source, "rb") as src: elffile = ELFFile(src)