[PATCH] Fix ELF e_flags propagation through built-in.o construction

From: David Howells
Date: Thu Aug 21 2014 - 08:48:43 EST


The built-in.o files are constructed in one of two ways:

(1) If there are contributory .o files, an incremental link (ld -r) is
performed to generate built-in.o.

(2) If there are _no_ contributory .o files, an empty archive file (ar) is
generated as built-in.o.

Unfortunately, with (2), if this is then incrementally linked into another
built-in.o file, the e_flags field in the ELF header may not have been set.
For instance, compare:

>sh64-linux-gnu-ar rcsD a.o
>sh64-linux-gnu-ld -r -EL -mshlelf64 -belf64-sh64l -o b.o a.o
>sh64-linux-gnu-readelf -h b.o | grep Flags
Flags: 0x0

to:

>sh64-linux-gnu-gcc -x c -c - -o zero.o </dev/null
>sh64-linux-gnu-readelf -h zero.o | grep Flags
Flags: 0xa, sh5

Attempting to further incrementally link b.o generated above gets an error
because e_flags is not set.

>sh64-linux-gnu-ld -r -EL -mshlelf64 -belf64-sh64l -o c.o b.o
sh64-linux-gnu-ld: unknown architecture of input file `b.o' is incompatible with sh5 output

Further, but probably not relevant to the kernel, if an archive file is
constructed that has some constituent object files in it, passing that to an
incremental link, eg:

#!/bin/sh -x
CROSS=sh64-linux-gnu-
LDFLAGS="-EL -mshlelf64 -belf64-sh64l"
#LDARFLAGS=--whole-archive
CFLAGS="-m5-64media-nofpu -ml"
rm -f hello.o wibble.o foo.o bar.o
echo 'int hello(int i) {return i + 42;}' |
${CROSS}gcc $CFLAGS -x c -c - -o hello.o || exit $?
${CROSS}readelf -h hello.o | grep Flags
${CROSS}ar rcsD wibble.o hello.o || exit $?
${CROSS}ld $LDFLAGS $LDARFLAGS -r -o foo.o wibble.o || exit $?
${CROSS}readelf -h foo.o | grep Flags
${CROSS}ld $LDFLAGS -r -o bar.o foo.o || exit $?
${CROSS}readelf -h bar.o | grep Flags

won't propagate e_flags _unless_ --whole-archive is also passed to the linker.

+ CROSS=sh64-linux-gnu-
+ LDFLAGS='-EL -mshlelf64'
+ CFLAGS='-m5-64media-nofpu -ml'
+ rm -f hello.o wibble.o foo.o bar.o
+ echo 'int hello(int i) {return i + 42;}'
+ sh64-linux-gnu-gcc -m5-64media-nofpu -ml -x c -c - -o hello.o
+ sh64-linux-gnu-readelf -h hello.o
+ grep Flags
Flags: 0xa, sh5
+ sh64-linux-gnu-ar rcsD wibble.o hello.o
+ sh64-linux-gnu-ld -EL -mshlelf64 -r -o foo.o wibble.o
+ sh64-linux-gnu-readelf -h foo.o
+ grep Flags
Flags: 0x0
+ sh64-linux-gnu-ld -EL -mshlelf64 -r -o bar.o foo.o
sh64-linux-gnu-ld: unknown architecture of input file `foo.o' is incompatible with sh5 output

To this end, change the construction of empty built-in.o files (case (2)
above) to use gcc on an empty file.

There is a binutils bug logged for this:

https://sourceware.org/bugzilla/show_bug.cgi?id=17288

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---
0 files changed

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index bf3e6778cd71..5bd80ef22866 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -330,7 +330,7 @@ quiet_cmd_link_o_target = LD $@
cmd_link_o_target = $(if $(strip $(obj-y)),\
$(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
$(cmd_secanalysis),\
- rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
+ $(CC) $(c_flags) -x c -c - -o $@ </dev/null)

$(builtin-target): $(obj-y) FORCE
$(call if_changed,link_o_target)

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/