[PATCH v2] m68k: Add LTO support

Angelo Dureghello angelo at kernel-space.org
Tue Mar 31 09:37:02 CEST 2026


Hi Daniel,

looks quite good to me, will re-test it asap, just have a questions:

On 3/31/26 00:01, Daniel Palmer wrote:
> Most m68k retro/homebrew machines will have limited flash/RAM
> so having LTO working would be nice.
> 
> Not many changes are need really. Most of this is copy/paste
> from the ARM32 version.
> 
> The major change is that the direct register usage of d7 for gd
> needs to be hidden so that when LTO passes over everything it
> doesn't see multiple instances of d7.
> 
> Signed-off-by: Daniel Palmer <daniel at thingy.jp>
> ---
>  arch/Kconfig                        |  1 +
>  arch/m68k/config.mk                 |  8 ++++++--
>  arch/m68k/cpu/m680x0/cpu.c          |  2 +-
>  arch/m68k/include/asm/global_data.h | 19 +++++++++++++++++++
>  arch/m68k/lib/ashldi3.c             |  6 ++++--
>  arch/m68k/lib/lshrdi3.c             |  6 ++++--
>  arch/m68k/lib/muldi3.c              |  4 +++-
>  common/board_r.c                    |  4 ++--
>  common/init/board_init.c            |  4 ++--
>  9 files changed, 42 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/Kconfig b/arch/Kconfig
> index 4af0da2485fb..488de442f557 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -112,6 +112,7 @@ config ARM
>  
>  config M68K
>  	bool "M68000 architecture"
> +	select ARCH_SUPPORTS_LTO
>  	select HAVE_PRIVATE_LIBGCC
>  	select USE_PRIVATE_LIBGCC
>  	select SYS_BOOT_GET_CMDLINE
> diff --git a/arch/m68k/config.mk b/arch/m68k/config.mk
> index 458953f97122..4d8c83b51cdb 100644
> --- a/arch/m68k/config.mk
> +++ b/arch/m68k/config.mk
> @@ -8,9 +8,13 @@ ifneq ($(CONFIG_M680x0),y)
>  PLATFORM_CPPFLAGS += -fPIC
>  endif
>  KBUILD_LDFLAGS    += -n -pie
> -PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections
>  PLATFORM_RELFLAGS += -ffixed-d7
>  ifneq ($(CONFIG_M680x0),y)
>  PLATFORM_RELFLAGS += -msep-data
>  endif
> -LDFLAGS_FINAL     += --gc-sections -pie
> +LDFLAGS_FINAL     += -pie
> +
> +ifneq ($(LTO_ENABLE),y)
> +PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections
> +LDFLAGS_FINAL     += --gc-sections
> +endif
> diff --git a/arch/m68k/cpu/m680x0/cpu.c b/arch/m68k/cpu/m680x0/cpu.c
> index f60b932c7dd4..3f87076b8c3d 100644
> --- a/arch/m68k/cpu/m680x0/cpu.c
> +++ b/arch/m68k/cpu/m680x0/cpu.c
> @@ -24,7 +24,7 @@ void m68k_virt_init_reserve(ulong base)
>  	for (i = 0; i < sizeof(*gd_ptr); i++)
>  		p[i] = 0;
>  
> -	gd = gd_ptr;
> +	arch_setup_gd(gd);
>  
>  	gd->malloc_base = base + sizeof(*gd_ptr);
>  }
> diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
> index aea2ccabe083..9150ed4ab466 100644
> --- a/arch/m68k/include/asm/global_data.h
> +++ b/arch/m68k/include/asm/global_data.h
> @@ -32,6 +32,25 @@ struct arch_global_data {
>  
>  #include <asm-generic/global_data.h>
>  
> +#if defined(LTO_ENABLE)
> +/* If LTO is enabled we have to hide d7 to avoid multiple symbol declarations */
> +#define DECLARE_GLOBAL_DATA_PTR
> +#define gd	get_gd()
> +
> +static inline gd_t *get_gd(void)
> +{
> +	gd_t *gd_ptr;
> +
> +	__asm__ volatile("move.l %%d7, %0\n" : "=r" (gd_ptr));
> +
> +	return gd_ptr;
> +}
> +#else
>  #define DECLARE_GLOBAL_DATA_PTR     register gd_t *gd asm ("d7")
> +#endif
> +static inline void arch_setup_gd(gd_t *new_gd)
> +{
> +	__asm__ volatile("move.l %0, %%d7\n" : : "r" (new_gd));
> +}
>  
>  #endif /* __ASM_GBL_DATA_H */
> diff --git a/arch/m68k/lib/ashldi3.c b/arch/m68k/lib/ashldi3.c
> index 9a4bc676bf4c..9e84bd0d9a07 100644
> --- a/arch/m68k/lib/ashldi3.c
> +++ b/arch/m68k/lib/ashldi3.c
> @@ -6,6 +6,8 @@
>   * Copyright (C) 1989-2015 Free Software Foundation, Inc.
>   */
>  
> +#include <linux/compiler_attributes.h>
> +
>  #define BITS_PER_UNIT 8
>  
>  typedef		 int SItype	__attribute__ ((mode (SI)));
> @@ -21,7 +23,7 @@ typedef union
>    DItype ll;
>  } DIunion;
>  
> -DItype __ashldi3 (DItype u, word_type b)
> +__used DItype __ashldi3 (DItype u, word_type b)

Why the above __used is needed ? This impacts all the coldfire builds. 

>  {
>  	DIunion w;
>  	word_type bm;
> @@ -46,4 +48,4 @@ DItype __ashldi3 (DItype u, word_type b)
>  	}
>  
>  	return w.ll;
> -}
> \ No newline at end of file
> +}
> diff --git a/arch/m68k/lib/lshrdi3.c b/arch/m68k/lib/lshrdi3.c
> index e639e676a269..53163bc5f83f 100644
> --- a/arch/m68k/lib/lshrdi3.c
> +++ b/arch/m68k/lib/lshrdi3.c
> @@ -6,6 +6,8 @@
>   * Copyright (C) 1989-2015 Free Software Foundation, Inc.
>   */
>  
> +#include <linux/compiler_attributes.h>
> +
>  #define BITS_PER_UNIT 8
>  
>  typedef		 int SItype	__attribute__ ((mode (SI)));
> @@ -21,7 +23,7 @@ typedef union
>    DItype ll;
>  } DIunion;
>  
> -DItype __lshrdi3 (DItype u, word_type b)
> +__used DItype __lshrdi3 (DItype u, word_type b)
>  {
>  	DIunion w;
>  	word_type bm;
> @@ -46,4 +48,4 @@ DItype __lshrdi3 (DItype u, word_type b)
>  	}
>  
>  	return w.ll;
> -}
> \ No newline at end of file
> +}
> diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c
> index c42ca1d753e5..06af5533fde3 100644
> --- a/arch/m68k/lib/muldi3.c
> +++ b/arch/m68k/lib/muldi3.c
> @@ -6,6 +6,8 @@
>   * Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
>   */
>  
> +#include <linux/compiler_attributes.h>
> +
>  #define SI_TYPE_SIZE 32
>  #define __BITS4 (SI_TYPE_SIZE / 4)
>  #define __ll_B (1L << (SI_TYPE_SIZE / 2))
> @@ -54,7 +56,7 @@ typedef union
>  	DItype ll;
>  } DIunion;
>  
> -DItype __muldi3 (DItype u, DItype v)
> +__used DItype __muldi3 (DItype u, DItype v)
>  {
>  	DIunion w;
>  	DIunion uu, vv;
> diff --git a/common/board_r.c b/common/board_r.c
> index 76f9fc090fbe..58eb69005468 100644
> --- a/common/board_r.c
> +++ b/common/board_r.c
> @@ -800,12 +800,12 @@ void board_init_r(gd_t *new_gd, ulong dest_addr)
>  	 * TODO(sjg at chromium.org): Consider doing this for all archs, or
>  	 * dropping the new_gd parameter.
>  	 */
> -	if (CONFIG_IS_ENABLED(X86_64) && !IS_ENABLED(CONFIG_EFI_APP))
> +	if ((CONFIG_IS_ENABLED(X86_64) && !IS_ENABLED(CONFIG_EFI_APP)) || CONFIG_IS_ENABLED(M68K))
>  		arch_setup_gd(new_gd);
>  
>  #if defined(CONFIG_RISCV)
>  	set_gd(new_gd);
> -#elif !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
> +#elif !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64) && !defined(CONFIG_M68K)
>  	gd = new_gd;
>  #endif
>  	gd->flags &= ~GD_FLG_LOG_READY;
> diff --git a/common/init/board_init.c b/common/init/board_init.c
> index 2a6f39f51adb..31b499ebad9c 100644
> --- a/common/init/board_init.c
> +++ b/common/init/board_init.c
> @@ -14,10 +14,10 @@
>  DECLARE_GLOBAL_DATA_PTR;
>  
>  /*
> - * Unfortunately x86, ARM and RISC-V can't compile this code as gd is defined
> + * Unfortunately x86, ARM, RISC-V, M68K can't compile this code as gd is defined
>   * as macro and cannot be assigned.
>   */
> -#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_RISCV)
> +#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_RISCV) && !defined(CONFIG_M68K)
>  __weak void arch_setup_gd(struct global_data *gd_ptr)
>  {
>  	gd = gd_ptr;


Regards,
-- Angelo



More information about the U-Boot mailing list