[1/1] toolchain: Fix ld.so copying for multilib toolchains.

Message ID 20180629113339.59102-1-christoph.muellner@theobroma-systems.com
State Changes Requested
Headers show
Series
  • [1/1] toolchain: Fix ld.so copying for multilib toolchains.
Related show

Commit Message

Christoph Müllner June 29, 2018, 11:33 a.m.
Multilib toolchains can have more than one ld.so files in lib/.
Typically one for each lib* directory.
However the current copy_toolchain_sysroot implemenation does
not support more than one ld.so.

This patch addresses this by iterating over all ld.so files
in the lib/ directory and choose the one, which has a symlink
into $ARCH_LIB_DIR/.

An example is a multilib toolchain for aarch64 (LP64 and ILP32),
which includes the following entries in lib/:

$ ls -l lib/
lrwxrwxrwx 1 user group ld-linux-aarch64_ilp32.so.1 -> ../libilp32/ld-2.27.so
lrwxrwxrwx 1 user group ld-linux-aarch64.so.1 -> ../lib64/ld-2.27.so

$ARCH_LIB_DIR/ will be detected as lib64.
Without the patch no ld.so will be copied.
With the patch the second ld.so (the one for LP64) will be copied.

Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
---
 toolchain/helpers.mk | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

Comments

Christoph Müllner June 29, 2018, 11:59 a.m. | #1
> On 29.06.2018, at 13:40, Thomas Petazzoni <thomas.petazzoni@bootlin.com> wrote:
> 
> Hello Christoph,
> 
> Thanks for this contribution!
> 
> On Fri, 29 Jun 2018 13:33:39 +0200, Christoph Muellner wrote:
>> Multilib toolchains can have more than one ld.so files in lib/.
>> Typically one for each lib* directory.
>> However the current copy_toolchain_sysroot implemenation does
>> not support more than one ld.so.
>> 
>> This patch addresses this by iterating over all ld.so files
>> in the lib/ directory and choose the one, which has a symlink
>> into $ARCH_LIB_DIR/.
>> 
>> An example is a multilib toolchain for aarch64 (LP64 and ILP32),
>> which includes the following entries in lib/:
>> 
>> $ ls -l lib/
>> lrwxrwxrwx 1 user group ld-linux-aarch64_ilp32.so.1 -> ../libilp32/ld-2.27.so
>> lrwxrwxrwx 1 user group ld-linux-aarch64.so.1 -> ../lib64/ld-2.27.so
>> 
>> $ARCH_LIB_DIR/ will be detected as lib64.
>> Without the patch no ld.so will be copied.
>> With the patch the second ld.so (the one for LP64) will be copied.
>> 
>> Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
>> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> 
> Is it possible to access the problematic toolchain ?

Toolchain can be downloaded here:

https://www.theobroma-systems.com/go/amp-7.3.0

I've been building an aarch64 image on an x86_64 host with
the amp-7.3.0-20180630-crosstools toolchain.

Among other things, this toolchain has LP64 and ILP32 support for aarch64.
The LP64 loader can be found here: $sysroot/lib/ld-linux-aarch64.so.1
The ILP64 loader can be found here: $sysroot/lib/ld-linux-aarch64_ilp32.so.1

Infos about aarch64 ILP32 can be found here:
https://wiki.linaro.org/Platform/arm64-ilp32

In my particular use case I'm building for LP64 (compiler default).
Buildroot detects this correctly ($ARCH_LIB_DIR will be "$sysroot/lib64")

The $sysroot is located here: amp-7.3.0-20180630/aarch64-amp-linux-gnu/sysroot
The loaders are in $sysroot/lib:

  ld-linux-aarch64_ilp32.so.1 -> ../libilp32/ld-2.27.so #ILP32
  ld-linux-aarch64.so.1 -> ../lib64/ld-2.27.so #LP64

Now the test "[ -e $${ARCH_SYSROOT_DIR}/lib/ld*.so.* ]" triggers
a syntax error, because "[ -e ld1.so ld2.so ];" is invalid syntax.

What the patch does here is to iterate over all ld*.so* files in $sysroot/lib
and checks if the given LD_SO is a symlink into $ARCH_LIB_DIR,
which is true for "ld-linux-aarch64.so.1 -> ../lib64/ld-2.27.so" in the LP64 case.

Thanks,
Christoph

> It would be useful to understand better the problem, and potentially
> add some test cases to verify that future changes in the external
> toolchain logic does not break this special situation.
> 
> Thanks,
> 
> Thomas
> --
> Thomas Petazzoni, CTO, Bootlin (formerly Free Electrons)
> Embedded Linux and Kernel engineering
> https://bootlin.com
> _______________________________________________
> buildroot mailing list
> buildroot@busybox.net
> http://lists.busybox.net/mailman/listinfo/buildroot
Thomas De Schampheleire Feb. 4, 2019, 2:12 p.m. | #2
Hello,

El vie., 29 jun. 2018 a las 13:51, Christoph Muellner
(<christoph.muellner@theobroma-systems.com>) escribió:
>
> Multilib toolchains can have more than one ld.so files in lib/.
> Typically one for each lib* directory.
> However the current copy_toolchain_sysroot implemenation does
> not support more than one ld.so.
>
> This patch addresses this by iterating over all ld.so files
> in the lib/ directory and choose the one, which has a symlink
> into $ARCH_LIB_DIR/.
>
> An example is a multilib toolchain for aarch64 (LP64 and ILP32),
> which includes the following entries in lib/:
>
> $ ls -l lib/
> lrwxrwxrwx 1 user group ld-linux-aarch64_ilp32.so.1 -> ../libilp32/ld-2.27.so
> lrwxrwxrwx 1 user group ld-linux-aarch64.so.1 -> ../lib64/ld-2.27.so
>
> $ARCH_LIB_DIR/ will be detected as lib64.
> Without the patch no ld.so will be copied.
> With the patch the second ld.so (the one for LP64) will be copied.
>
> Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
> Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
> ---
>  toolchain/helpers.mk | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)

Please extend the commit message and refer to the toolchain in which
you found this problem, with its link.
This will help future analysis when more rework in this area is needed.

>
> diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
> index 1792286add..62c0454be5 100644
> --- a/toolchain/helpers.mk
> +++ b/toolchain/helpers.mk
> @@ -136,9 +136,14 @@ copy_toolchain_sysroot = \
>                 done ; \
>         fi ; \
>         if [ ! -e $(STAGING_DIR)/lib/ld*.so.* ]; then \
> -               if [ -e $${ARCH_SYSROOT_DIR}/lib/ld*.so.* ]; then \
> -                       cp -a $${ARCH_SYSROOT_DIR}/lib/ld*.so.* $(STAGING_DIR)/lib/ ; \
> -               fi ; \
> +               find $${ARCH_SYSROOT_DIR}/lib/ -name ld*.so.* -print0 | while IFS= read -r -d '' LD_SO; do \
> +                       LINKTARGET=`realpath $${LD_SO}` ; \
> +                       LINKTARGETDIR=`dirname $${LINKTARGET}` ; \
> +                       LINKTARGETBASE=`basename $${LINKTARGETDIR}` ; \

This is more correctly 'LINKTARGETDIRBASE' not 'LINKTARGETBASE', i.e.
'LINKTARGETBASE' would be 'ld.so.xxxx'.

> +                       if [ "$${LINKTARGETBASE}" = "$${ARCH_LIB_DIR}" ]; then \
> +                               cp -a $${LD_SO} $(STAGING_DIR)/lib/ ; \
> +                       fi ; \
> +               done ; \

I tested the changes both for the specified toolchain as for the
Marvell-provided Octeon toolchain which is also multilib, and the
expected ld.so files are indeed present on the target.

However, the new code assumes that the ld.so file matched with the
find command is a symbolic link, and then assumes that it points to
something identifyable with ARCH_LIB_DIR. I don't know whether it
occurs in practice, but suppose:
a. a single file is found and it is a regular file
b. a single file is found, it is a symbolic link, but it points to
something that is not containing ARCH_LIB_DIR as base.
c. multiple files are found, they are not symbolic links.

Case a and b could be solved by falling back to a simple copy (of all
matched files) if the link-comparing approach is not resulting in a
match.
But case c is more complex. An alternative would be to actually
inspect the architecture using readelf and compare it to the expected
value, e.g. based on libc.a.

I don't know how far we should go...

Best regards,
Thomas

Patch

diff --git a/toolchain/helpers.mk b/toolchain/helpers.mk
index 1792286add..62c0454be5 100644
--- a/toolchain/helpers.mk
+++ b/toolchain/helpers.mk
@@ -136,9 +136,14 @@  copy_toolchain_sysroot = \
 		done ; \
 	fi ; \
 	if [ ! -e $(STAGING_DIR)/lib/ld*.so.* ]; then \
-		if [ -e $${ARCH_SYSROOT_DIR}/lib/ld*.so.* ]; then \
-			cp -a $${ARCH_SYSROOT_DIR}/lib/ld*.so.* $(STAGING_DIR)/lib/ ; \
-		fi ; \
+		find $${ARCH_SYSROOT_DIR}/lib/ -name ld*.so.* -print0 | while IFS= read -r -d '' LD_SO; do \
+			LINKTARGET=`realpath $${LD_SO}` ; \
+			LINKTARGETDIR=`dirname $${LINKTARGET}` ; \
+			LINKTARGETBASE=`basename $${LINKTARGETDIR}` ; \
+			if [ "$${LINKTARGETBASE}" = "$${ARCH_LIB_DIR}" ]; then \
+				cp -a $${LD_SO} $(STAGING_DIR)/lib/ ; \
+			fi ; \
+		done ; \
 	fi ; \
 	if [ `readlink -f $${SYSROOT_DIR}` != `readlink -f $${ARCH_SYSROOT_DIR}` ] ; then \
 		if [ ! -d $${ARCH_SYSROOT_DIR}/usr/include ] ; then \