[PATCH 1/2] ARM: fix nm error message when GNU Make >= 4.4 is used

From: Masahiro Yamada
Date: Sat Jan 07 2023 - 16:21:17 EST


Nathan Chancellor reports an error message from $(NM) if GNU Make 4.4
is used to build the ARM decompressor.

$ make-4.4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- O=build defconfig all
[snip]
LD vmlinux
NM System.map
SORTTAB vmlinux
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
arm-linux-gnueabi-nm: 'arch/arm/boot/compressed/../../../../vmlinux': No such file
/bin/sh: 1: arithmetic expression: expecting primary: " "
LDS arch/arm/boot/compressed/vmlinux.lds
AS arch/arm/boot/compressed/head.o
GZIP arch/arm/boot/compressed/piggy_data
AS arch/arm/boot/compressed/piggy.o
CC arch/arm/boot/compressed/misc.o

This occurs with GNU Make commit 98da874c4303 ("[SV 10593] Export
variables to $(shell ...) commands"), and the O= option is needed to
reproduce it. The generated zImage is correct despite the error message.

As the commit description of 98da874c4303 [1] says, exported variables
are passed down to $(shell ) functions, which means exported recursive
variables might be expanded earlier than before, in the parse stage.

The following test code demonstrates the change for GNU Make 4.4.

[Test Makefile]

$(shell echo hello > foo)
export foo = $(shell cat bar/../foo)
$(shell mkdir bar)

all:
@echo $(foo)

[GNU Make 4.3]

$ rm -rf bar; make-4.3
hello

[GNU Make 4.4]

$ rm -rf bar; make-4.4
cat: bar/../foo: No such file or directory
hello

The 'foo' is a resursively expanded (or lazily expanded) variable.

GNU Make 4.3 expands it just before running the recipe '@echo $(foo)',
at this point, the directory 'bar' exists.

GNU Make 4.4 expands it to evaluate $(shell mkdir bar) because 'foo' is
exported. At this point, the directory 'bar' does not exit yet. The cat
command cannot resolve the bar/../foo path, hence the error message.

Let's get back to the kernel Makefile.

'KBSS_SZ' in arch/arm/boot/compressed/Makefile is a recursive variable,
which is referenced by 'LDFLAGS_vmlinux', which is also a recursive
variable.

GNU Make 4.3 expands 'KBSS_SZ' just before running the recipes. Before
that, $(shell mkdir -p $(obj-dirs)) in scripts/Makefile.build creates
the output directory, arch/arm/boot/compressed.

GNU Make 4.4 expands 'KBSS_SZ' in the parse stage because LDFLAGS_vmlinux
was (accidentally) exported by commit 5d4aeffbf709 ("kbuild: rebuild
.vmlinux.export.o when its prerequisite is updated"). $(NM) cannot
resolve the path arch/arm/boot/compressed/../../../../vmlinux.

I admit this is a bug caused by 5d4aeffbf709 (I will fix it in the next
commit), but do not see any good reason in writing the vmlinux path in
such an indirect way. Just say 'vmlinux'.

[1]: https://git.savannah.gnu.org/cgit/make.git/commit/?id=98da874c43035a490cdca81331724f233a3d0c9a

Link: https://lore.kernel.org/all/Y7i8+EjwdnhHtlrr@dev-arch.thelio-3990X/
Fixes: 5d4aeffbf709 ("kbuild: rebuild .vmlinux.export.o when its prerequisite is updated")
Reported-by: Nathan Chancellor <nathan@xxxxxxxxxx>
Signed-off-by: Masahiro Yamada <masahiroy@xxxxxxxxxx>
---

arch/arm/boot/compressed/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 2ef651a78fa2..726ecabcef09 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -107,7 +107,7 @@ ccflags-remove-$(CONFIG_FUNCTION_TRACER) += -pg
asflags-y := -DZIMAGE

# Supply kernel BSS size to the decompressor via a linker symbol.
-KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
+KBSS_SZ = $(shell echo $$(($$($(NM) vmlinux | \
sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \
-e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) )
LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
--
2.34.1