Hi Daniel,
On Wed, Mar 11, 2026 at 06:30:48PM +0900, 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 <[email protected]>
> ---
>
> This is another patch from my vault that I have been using
> on various classic m68k machines for ages. I haven't tested
> it with coldfire though.
>
> arch/Kconfig | 1 +
> arch/m68k/config.mk | 11 +++++++++--
> arch/m68k/cpu/m680x0/cpu.c | 2 +-
> arch/m68k/include/asm/global_data.h | 19 +++++++++++++++++++
> arch/m68k/lib/ashldi3.c | 1 +
> arch/m68k/lib/lshrdi3.c | 1 +
> arch/m68k/lib/muldi3.c | 1 +
> common/board_r.c | 4 ++--
> common/init/board_init.c | 2 +-
> 9 files changed, 36 insertions(+), 6 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..1be46adda966 100644
> --- a/arch/m68k/config.mk
> +++ b/arch/m68k/config.mk
> @@ -8,9 +8,16 @@ 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)$(CONFIG_USE_PRIVATE_LIBGCC),yy)
> +LDFLAGS_FINAL += --gc-sections
> +endif
Maybe add a comment saying why we must drop --gc-sections when both LTO
and private libgcc are enabled?
> +
> +ifneq ($(LTO_ENABLE),y)
> +PLATFORM_RELFLAGS += -ffunction-sections -fdata-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);
I guess you mean arch_setup_gd(gd_ptr) here?
>
> 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..82bd9113ecbf 100644
> --- a/arch/m68k/lib/ashldi3.c
> +++ b/arch/m68k/lib/ashldi3.c
> @@ -21,6 +21,7 @@ typedef union
> DItype ll;
> } DIunion;
>
> +DItype __ashldi3 (DItype u, word_type b) __attribute__((used));
We have __used in linux/compiler.h, which I think is preferred over raw
__attribute__((used)).
Regards,
Kuan-Wei
> DItype __ashldi3 (DItype u, word_type b)
> {
> DIunion w;
> diff --git a/arch/m68k/lib/lshrdi3.c b/arch/m68k/lib/lshrdi3.c
> index e639e676a269..691d503d7313 100644
> --- a/arch/m68k/lib/lshrdi3.c
> +++ b/arch/m68k/lib/lshrdi3.c
> @@ -21,6 +21,7 @@ typedef union
> DItype ll;
> } DIunion;
>
> +DItype __lshrdi3 (DItype u, word_type b) __attribute__((used));
> DItype __lshrdi3 (DItype u, word_type b)
> {
> DIunion w;
> diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c
> index c42ca1d753e5..53d674701531 100644
> --- a/arch/m68k/lib/muldi3.c
> +++ b/arch/m68k/lib/muldi3.c
> @@ -54,6 +54,7 @@ typedef union
> DItype ll;
> } DIunion;
>
> +DItype __muldi3 (DItype u, DItype v) __attribute__((used));
> DItype __muldi3 (DItype u, DItype v)
> {
> DIunion w;
> 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([email protected]): 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..c56b33e7be7c 100644
> --- a/common/init/board_init.c
> +++ b/common/init/board_init.c
> @@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR;
> * Unfortunately x86, ARM and RISC-V 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;
> --
> 2.51.0
>