This is an archive of the discontinued LLVM Phabricator instance.

[Driver] Fix architecture triplets and search paths for Linux x32
ClosedPublic

Authored by hvdijk on Sep 13 2018, 12:01 PM.

Details

Summary

Currently, support for the x32 ABI is handled as a multilib to the
x86_64 target only. However, full self-hosting x32 systems treating it
as a separate architecture with its own architecture triplets as well as
search paths exist as well, in Debian's x32 port and elsewhere.

This adds the missing architecture triplets and search paths so that
clang can work as a native compiler on x32, and updates the tests so
that they pass when using an x32 libdir suffix.

Additionally, we would previously also assume that objects from any
x86_64-linux-gnu GCC installation could be used to target x32. This
changes the logic so that only GCC installations that include x32
support are used when targetting x32, meaning x86_64-linux-gnux32 GCC
installations, and x86_64-linux-gnu and i686-linux-gnu GCC installations
that include x32 multilib support.

Diff Detail

Event Timeline

glaubitz created this revision.Sep 13 2018, 12:01 PM
glaubitz updated this revision to Diff 302142.Nov 1 2020, 5:00 AM
glaubitz retitled this revision from [Driver] Fix search paths on x32 to [Driver] Fix architecture triplets and search paths for Linux x32.
glaubitz edited the summary of this revision. (Show Details)
glaubitz added reviewers: chandlerc, rengolin.

Rebase patch for monorepo, add Debian MultiArch tests.

Herald added a project: Restricted Project. · View Herald TranscriptNov 1 2020, 5:00 AM
Herald added a subscriber: pengfei. · View Herald Transcript

Can you upload the diff with full context (e.g. use diff -U 9999 or use arcanist to upload)?

I'm a bit confused; the commit message talks about X32 being a separate architecture, but you're not adding any new architecture triples here (it still uses x86_64 as the architecture and selects the ABI via the environment). AFAICS what really changes is that the structure of the include and lib directories is now multi-arch style with the x32 headers alongside the x86_64 base headers?

Can you upload the diff with full context (e.g. use diff -U 9999 or use arcanist to upload)?

I'm a bit confused; the commit message talks about X32 being a separate architecture, but you're not adding any new architecture triples here (it still uses x86_64 as the architecture and selects the ABI via the environment). AFAICS what really changes is that the structure of the include and lib directories is now multi-arch style with the x32 headers alongside the x86_64 base headers?

Updated diff coming in a bit.

As for the term architecture: It's a separate architecture in Debian which can also mean just a different ABI. In Debian terms, an architecture can be a different ABI, different real architecture or different kernel.

glaubitz updated this revision to Diff 302404.Nov 2 2020, 2:05 PM

Regenerated with more context (using git format-patch -W).

One other question then: do you know if Debian and/or Ubuntu still have the same support for running x32 programs on the regular x86-64 distribution? (presumably yes, since you aren't changing the existing behavior).
AFAIK clang's current support was developed against Ubuntu, but I haven't tried it in a long time and to my knowledge nobody has submitted any patches for x32 in a while either.

One other question then: do you know if Debian and/or Ubuntu still have the same support for running x32 programs on the regular x86-64 distribution? (presumably yes, since you aren't changing the existing behavior).
AFAIK clang's current support was developed against Ubuntu, but I haven't tried it in a long time and to my knowledge nobody has submitted any patches for x32 in a while either.

I have seen the testsuite failures and I have to verify that. What I know is that Ubuntu 14.04, against this was tested, is no longer supported.

I have to admit that I don't fully understand yet why the tests fail. I will verify what GCC does but I assume we have to update the other tests.

RKSimon added subscribers: hvdijk, RKSimon.

Adding @hvdijk as IIRC has been looking at gnux32 as well

Yeah, @hvdijk has made multiple other improvements which should finally allow the backend to be usable.

We still disagree on the search paths for libraries and headers though if I remember correctly.

My goal is to make LLVM and Rust work on an full Debian x32 system which is why we need dedicated Multi-Arch search paths such as /usr/lib/x86_64-linux-gnux32/.

Do we have any buildbot coverage for gnux32?

Yeah, @hvdijk has made multiple other improvements which should finally allow the backend to be usable.

We still disagree on the search paths for libraries and headers though if I remember correctly.

No disagreement. I hadn't done anything in this area only because my non-Debian system doesn't need it, not because I'm in any way opposed to this change. My knowledge of the Debian file system layout is a bit limited, but this change looks to me like it makes sense.

One other question then: do you know if Debian and/or Ubuntu still have the same support for running x32 programs on the regular x86-64 distribution? (presumably yes, since you aren't changing the existing behavior).
AFAIK clang's current support was developed against Ubuntu, but I haven't tried it in a long time and to my knowledge nobody has submitted any patches for x32 in a while either.

I have seen the testsuite failures and I have to verify that. What I know is that Ubuntu 14.04, against this was tested, is no longer supported.

I have to admit that I don't fully understand yet why the tests fail. I will verify what GCC does but I assume we have to update the other tests.

Were you able to compare against GCC and also determine debian/ubuntu's x86_64 current support for x32 executables?

Were you able to compare against GCC and also determine debian/ubuntu's x86_64 current support for x32 executables?

Not yet. Currently freeing up space on my VM host so I can perform a fresh Ubuntu installation to make sure I have verified that Debian and Ubuntu don't deviate here.

Just as a heads-up, I haven't forgotten about this. Freeing up the server just takes a little longer as I need to backup files through a DSL line. Should be ready by tomorrow.

I stumbled over one problem with my patch which is that when I run an x32 version of clang in a x32 environment, it will still default to "-m64" instead of "-mx32".

Thus:

glaubitz@epyc:..llvm-project/build> ./bin/clang hello.c -o hello
/usr/bin/ld: cannot find crtbegin.o: No such file or directory
/usr/bin/ld: cannot find -lgcc
/usr/bin/ld: cannot find -lgcc_s
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
glaubitz@epyc:..llvm-project/build> ./bin/clang -mx32 hello.c -o hello
glaubitz@epyc:..llvm-project/build> file hello
hello: ELF 32-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /libx32/ld-linux-x32.so.2, for GNU/Linux 3.4.0, not stripped
glaubitz@epyc:..llvm-project/build> file bin/clang-12
bin/clang-12: ELF 32-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /libx32/ld-linux-x32.so.2, BuildID[sha1]=6175851930c1e79df16060c731ecda2f596ef05a, for GNU/Linux 3.4.0, not stripped
glaubitz@epyc:..llvm-project/build>

Any idea how it could make clang default to -mx32 if this condition is met: getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32?

hvdijk added a comment.Dec 2 2020, 8:01 AM

Any idea how it could make clang default to -mx32 if this condition is met: getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32?

That sounds like it's one thing in https://lists.llvm.org/pipermail/llvm-dev/2020-October/146049.html I haven't extracted into a separate patch for submission yet: LLVM does not call Triple::normalize everywhere it should, and misinterprets x86_64-linux-gnux32 as x86_64-somethingelse when it's set as the default target because of it. For testing this change, it may be easiest to just explicitly specify the triple or -mx32.

That sounds like it's one thing in https://lists.llvm.org/pipermail/llvm-dev/2020-October/146049.html I haven't extracted into a separate patch for submission yet: LLVM does not call Triple::normalize everywhere it should, and misinterprets x86_64-linux-gnux32 as x86_64-somethingelse when it's set as the default target because of it. For testing this change, it may be easiest to just explicitly specify the triple or -mx32.

That doesn't help, unfortunately

The problem is that invoking clang on a Debian x32 defaults to -m64 while it should default to -mx32. See my test run above.

I have not found the place yet in clang where to adjust that.

I have not found the place yet in clang where to adjust that.

Maybe sys::getDefaultTargetTriple() needs to be adjusted. I'll have a look.

hvdijk added a comment.Dec 2 2020, 9:03 AM

Maybe sys::getDefaultTargetTriple() needs to be adjusted. I'll have a look.

sys::getDefaultTargetTriple() defaults to LLVM_DEFAULT_TARGET_TRIPLE, which in turn defaults to LLVM_HOST_TRIPLE, which in turn defaults to LLVM_INFERRED_HOST_TRIPLE, which calls config.guess which never automatically detects X32. Sorry, forgot to mention that on my system, I also make sure to explicitly specify LLVM_HOST_TRIPLE to an X32 triple when building LLVM.

The problem seems to be that LLVM_HOST_TRIPLE:STRING is set to x86_64-unknown-linux-gnu instead of `x86_64-unknown-linux-gnux32.

I haven't found the place to fix that yet.

sys::getDefaultTargetTriple() defaults to LLVM_DEFAULT_TARGET_TRIPLE, which in turn defaults to LLVM_HOST_TRIPLE, which in turn defaults to LLVM_INFERRED_HOST_TRIPLE, which calls config.guess which never automatically detects X32. Sorry, forgot to mention that on my system, I also make sure to explicitly specify LLVM_HOST_TRIPLE to an X32 triple when building LLVM.

Hmm, I was pretty sure that autoconf can deal with x32 inside an x32 chroot.

hvdijk added a comment.Dec 2 2020, 9:12 AM

Hmm, I was pretty sure that autoconf can deal with x32 inside an x32 chroot.

Most autoconf-using software won't be dealing with a copy of config.guess that was last updated in 2011. Updating that to a more recent version should also work. :)

Hmm, I was pretty sure that autoconf can deal with x32 inside an x32 chroot.

Most autoconf-using software won't be dealing with a copy of config.guess that was last updated in 2011. Updating that to a more recent version should also work. :)

Ah, yes, that actually explains the problem :). Thanks a lot!

jrtc27 added a comment.Dec 2 2020, 9:17 AM

Hmm, I was pretty sure that autoconf can deal with x32 inside an x32 chroot.

Most autoconf-using software won't be dealing with a copy of config.guess that was last updated in 2011. Updating that to a more recent version should also work. :)

Debian's config.guess supports x32, and the patch to do that in a way upstream was happy with finally landed earlier this year after being a long-standing issue.

hvdijk added a comment.Dec 8 2020, 1:57 PM

I've been able to check what Ubuntu 20.10 offers in terms of x32 support. Its kernel supports x32 binaries, it provides x32 versions of core system libraries in separate packages (e.g. libc6-x32, libx32stdc++6, libx32z1), and it provides a compiler that targets x32 by default (gcc-x86-64-linux-gnux32). These Ubuntu packages do not use the Debian/Ubuntu multiarch approach: the packages are completely independent of the corresponding x64 and i386 versions with separate names, and nothing in Ubuntu installs any libraries into any /lib/x86_64-linux-gnux32-like path. They are intended to allow x32 cross compilation on an Ubuntu system, not intended to act as a basis for running an x32 Ubuntu system. This appears to be very different from Debian's x32 support. That said, cross-compiled binaries do run on Ubuntu and it should be possible to build an x32-native LLVM with the Ubuntu-provided toolchain.

glaubitz added a comment.EditedDec 8 2020, 2:18 PM

I've been able to check what Ubuntu 20.10 offers in terms of x32 support. Its kernel supports x32 binaries, it provides x32 versions of core system libraries in separate packages (e.g. libc6-x32, libx32stdc++6, libx32z1), and it provides a compiler that targets x32 by default (gcc-x86-64-linux-gnux32).

I did that, too. In fact, Ubuntu is identical to Debian in this regard as both the Ubuntu and the Debian gcc packages are maintained by the same maintainer (Matthias Klose whom I also happen to know personally) who first uploads these packages to Debian unstable, then syncs to Ubuntu.

However:

These Ubuntu packages do not use the Debian/Ubuntu multiarch approach: the packages are completely independent of the corresponding x64 and i386 versions with separate names, and nothing in Ubuntu installs any libraries into any /lib/x86_64-linux-gnux32-like path. They are intended to allow x32 cross compilation on an Ubuntu system, not intended to act as a basis for running an x32 Ubuntu system. This appears to be very different from Debian's x32 support. That said, cross-compiled binaries do run on Ubuntu and it should be possible to build an x32-native LLVM with the Ubuntu-provided toolchain.

Well, Debian has both as - as I already mentioned - the gcc packages in Debian and Ubuntu are the same. The only difference is that Ubuntu does not provide an x32 port so there is no possibility to install Ubuntu x32 packages in the commonly known MultiArch manner.

Since MultiArch and the -cross packages are somewhat redundant, I'm not so sure yet which approach to address this issue would be best. I will talk to Matthias regarding this.

jrtc27 added a comment.Dec 8 2020, 2:23 PM

I've been able to check what Ubuntu 20.10 offers in terms of x32 support. Its kernel supports x32 binaries, it provides x32 versions of core system libraries in separate packages (e.g. libc6-x32, libx32stdc++6, libx32z1), and it provides a compiler that targets x32 by default (gcc-x86-64-linux-gnux32).

I did that, too. In fact, Ubuntu is identical to Debian in this regard as both the Ubuntu and the Debian gcc packages are maintained by the same maintainer (Matthias Klose whom I also happen to know personally) who first uploads these packages to Debian unstable, then syncs to Ubuntu.

However:

These Ubuntu packages do not use the Debian/Ubuntu multiarch approach: the packages are completely independent of the corresponding x64 and i386 versions with separate names, and nothing in Ubuntu installs any libraries into any /lib/x86_64-linux-gnux32-like path. They are intended to allow x32 cross compilation on an Ubuntu system, not intended to act as a basis for running an x32 Ubuntu system. This appears to be very different from Debian's x32 support. That said, cross-compiled binaries do run on Ubuntu and it should be possible to build an x32-native LLVM with the Ubuntu-provided toolchain.

Well, Debian has both as - as I already mentioned - the gcc packages in Debian and Ubuntu are the same. The only difference is that Ubuntu does not provide an x32 port so there is no possibility to install Ubuntu x32 packages in the commonly known MultiArch manner.

Since MultiArch and the -cross packages are somewhat redundant, I'm not so sure yet which approach to address this issue would be best. I will talk to Matthias regarding this.

What gets done currently for i386? That suffers potentially the same problem given both /usr/lib/gcc/x86_64-linux-gnu/$V/32 and /usr/lib/gcc/i386-linux-gnu/$V are possible locations for an i386 GCC toolchain.

jrtc27 added a comment.Dec 8 2020, 2:24 PM

i.e. can we not just support both approaches and prefer x86_64-linux-gnux32 if it exists?

What gets done currently for i386? That suffers potentially the same problem given both /usr/lib/gcc/x86_64-linux-gnu/$V/32 and /usr/lib/gcc/i386-linux-gnu/$V are possible locations for an i386 GCC toolchain.

Very good suggestion. I will look into that tomorrow. Thanks for the pointer!

glaubitz added a comment.EditedDec 21 2020, 1:45 PM

What gets done currently for i386? That suffers potentially the same problem given both /usr/lib/gcc/x86_64-linux-gnu/$V/32 and /usr/lib/gcc/i386-linux-gnu/$V are possible locations for an i386 GCC toolchain.

Very good suggestion. I will look into that tomorrow. Thanks for the pointer!

I have been wrapping my head around this for some time and I have run into one problem trying to apply the suggested approach.

The problem is that I don't know how to tell whether I'm on an x86_64 system or an x32 system there is no `case llvm::Triple::x32:` which would be needed here (we have it for x86).

x32 takes the switch case for x86_64, so x32 and x86_64 targeting x32 are identical.

However, that's not the same as whether we're on an x86_64 system or on an x32 system determines which GNU triplet to use and which include and library search paths are our primary ones.

However, that's not the same as whether we're on an x86_64 system or on an x32 system determines which GNU triplet to use and which include and library search paths are our primary ones.

I don't see why it should?
When you target i386-linux-gnu, you can use objects from /usr/lib/gcc/i386-linux-gnu/*, /usr/lib/gcc/x86_64-linux-gnu/*/32, and /usr/lib/gcc/x86_64-linux-gnux32/*/32.
When you target x86_64-linux-gnu, you can use objects from /usr/lib/gcc/x86_64-linux-gnu/*, /usr/lib/gcc/x86_64-linux-gnux32/*/64, and /usr/lib/gcc/i386-linux-gnu/*/64.
When you target x86_64-linux-gnux32, you can use objects from /usr/lib/gcc/x86_64-linux-gnux32/*, /usr/lib/gcc/x86_64-linux-gnu/*/x32, and /usr/lib/gcc/i386-linux-gnu/*/x32.
All cases should be read to include all variants of the triples as well. None of that depends on the LLVM host architecture, does it? The LLVM host architecture makes it more or less likely that a GCC installation will be found in any of the listed directories, but not how it should be handled if found.

What gets done currently for i386? That suffers potentially the same problem given both /usr/lib/gcc/x86_64-linux-gnu/$V/32 and /usr/lib/gcc/i386-linux-gnu/$V are possible locations for an i386 GCC toolchain.

Very good suggestion. I will look into that tomorrow. Thanks for the pointer!

I have been wrapping my head around this for some time and I have run into one problem trying to apply the suggested approach.

The problem is that I don't know how to tell whether I'm on an x86_64 system or an x32 system there is no `case llvm::Triple::x32:` which would be needed here (we have it for x86).

x32 takes the switch case for x86_64, so x32 and x86_64 targeting x32 are identical.

However, that's not the same as whether we're on an x86_64 system or on an x32 system determines which GNU triplet to use and which include and library search paths are our primary ones.

But Triple.getEnvironment() will give you llvm::Triple::GNUX32 that you can check?

glaubitz added a comment.EditedJan 4 2021, 5:36 AM

However, that's not the same as whether we're on an x86_64 system or on an x32 system determines which GNU triplet to use and which include and library search paths are our primary ones.

But Triple.getEnvironment() will give you llvm::Triple::GNUX32 that you can check?

Yes, but we have to differentiate four scenarios:

  • On x86_64, targeting x86_64
  • On x86_64, targeting x32
  • On x32, targeting x32
  • On x32, targeting x86_64

On x86 it's clear because "x86" is an architecture on its own from clang's point of view. But that doesn't apply for x32 (at least for clang) and hence I don't know how to differentiate these four scenarios.

If anyone can suggest a better patch than my current patch, I would be happy to test it though.

One other question then: do you know if Debian and/or Ubuntu still have the same support for running x32 programs on the regular x86-64 distribution?

I am not sure that I right understand reason of this question, but there is gentoo x32 profile that allow execute all arch x86, x32, x64.

One other question then: do you know if Debian and/or Ubuntu still have the same support for running x32 programs on the regular x86-64 distribution?

I am not sure that I right understand reason of this question, but there is gentoo x32 profile that allow execute all arch x86, x32, x64.

There are two ways to use x32. Either as a sub-architecture of x86_64 with x32-subfolders in /usr/lib/gcc/x86_64-linux-gnu/ (and so on) and as a separate, dedicated port.

Debian supports both and I am trying to fix the separate port with this patch.

I think I will resume working on this next week as I would like to finally get this fixed.

Hmm, there recently were quite some changes in the MultiArch and GCC search path functionality in the Driver and I can unfortunately no longer get it to work on x32.

I had a relatively simple approach but I cannot get it to add the path for the crt.o objects and so on. It's always searching in the wrong paths.

MaskRay added inline comments.Mar 29 2021, 7:50 PM
clang/lib/Driver/ToolChains/Gnu.cpp
2091

Just add x86_64-linux-gnux32. It is sufficient for Debian. Only add others when needed.

clang/lib/Driver/ToolChains/Linux.cpp
90

I have cleaned up the code a bit. You may need to rebase.

glaubitz added inline comments.Mar 30 2021, 1:28 AM
clang/lib/Driver/ToolChains/Linux.cpp
90

Yeah, I have done that but not uploaded my latest diff yet (which doesn't work on x32, unfortunately). I will do that now.

glaubitz updated this revision to Diff 334071.Mar 30 2021, 1:32 AM
glaubitz retitled this revision from [Driver] Fix architecture triplets and search paths for Linux x32 to WIP: [Driver] Fix architecture triplets and search paths for Linux x32.

Updated version which unfortunately still fails.

One of the problems is that I don't know how to detect a native x32 system
in getOSLibDir() in clang/lib/Driver/ToolChains/Linux.cpp.

On a native x32 system, libraries are not in /libx32.

I may be missing something, but I do not understand the problem. What systems, other than Debian multi-arch, are you looking to also add support for? My own native x32 system uses (/usr)/libx32 for x32 libraries. Debian uses (/usr)/lib/x86_64-linux-gnux32. I can understand if some people might use (/usr)/lib without any x32 suffix, though I am not aware of anyone doing this. Where does lib32 come from, though? What other systems are you trying to account for?

I may have some spare time soon, I can take a look and do some testing as well.

clang/lib/Driver/ToolChains/Linux.cpp
90

This should have a TargetEnvironment == llvm::Triple::GNUX32 check.

217

x86_64-linux-gnux32 never uses lib32, does it? It might use lib (mostly theoretical), or it might use libx32. Leaving this unmodified, always returning libx32 for x32, looks to me like it matches x86_64-linux-gnu, which always returns lib64 even though some people put libraries for that in /lib too.

I may be missing something, but I do not understand the problem. What systems, other than Debian multi-arch, are you looking to also add support for? My own native x32 system uses (/usr)/libx32 for x32 libraries. Debian uses (/usr)/lib/x86_64-linux-gnux32. I can understand if some people might use (/usr)/lib without any x32 suffix, though I am not aware of anyone doing this. Where does lib32 come from, though? What other systems are you trying to account for?

I have tried all kinds of variants of this patch on Debian x32 with MultiArch and can't get it to work because it uses the wrong search-paths for the libraries.
I am still convinced the problem is that LLVM does not understand x32 as a real distinct architecture unlike i386 which is why we cannot apply the same
logic for x32 and i386.

When the compiler tests TargetEnvironment == llvm::Triple::GNUX32, it does not know whether it's in a native x32 environment or just on an x86_64
system where the target triplet is set to x86_64-linux-gnux32 and I think that's the problem.

I may have some spare time soon, I can take a look and do some testing as well.

If you have a working fix for Debian x32, I would be happy to see it.

I am testing the below, on top of c8e56f394af0b9e32c413d62a0e7aebbba3e6b70, both in a Debian chroot and in my non-Debian system. Initial testing in the Debian chroot suggests that this works for simple cases, clang has no problem finding /usr/lib/gcc/x86_64-linux-gnux32/10, and also picks up the right crt*.o files when using -m32 or -m64. Will do more extensive testing.

--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2106,7 +2106,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
       "x86_64-manbo-linux-gnu", "x86_64-linux-gnu",
       "x86_64-slackware-linux", "x86_64-unknown-linux",
       "x86_64-amazon-linux",    "x86_64-linux-android"};
-  static const char *const X32LibDirs[] = {"/libx32"};
+  static const char *const X32Triples[] = {
+      "x86_64-linux-gnux32",    "x86_64-unknown-linux-gnux32",
+      "x86_64-pc-linux-gnux32"};
+  static const char *const X32LibDirs[] = {"/libx32", "/lib"};
   static const char *const X86LibDirs[] = {"/lib32", "/lib"};
   static const char *const X86Triples[] = {
       "i586-linux-gnu",     "i686-linux-gnu",
@@ -2337,17 +2340,19 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
     TripleAliases.append(begin(AVRTriples), end(AVRTriples));
     break;
   case llvm::Triple::x86_64:
-    LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
-    TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
-    // x32 is always available when x86_64 is available, so adding it as
-    // secondary arch with x86_64 triples
     if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
-      BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+      LibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+      TripleAliases.append(begin(X32Triples), end(X32Triples));
+      BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
       BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
     } else {
-      BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
-      BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
+      LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
+      TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+      BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+      BiarchTripleAliases.append(begin(X32Triples), end(X32Triples));
     }
+    BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
+    BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
     break;
   case llvm::Triple::x86:
     LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
@@ -2357,6 +2362,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
       TripleAliases.append(begin(X86Triples), end(X86Triples));
       BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
       BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
+      BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
+      BiarchTripleAliases.append(begin(X32Triples), end(X32Triples));
     }
     break;
   case llvm::Triple::m68k:

I am testing the below, on top of c8e56f394af0b9e32c413d62a0e7aebbba3e6b70, both in a Debian chroot and in my non-Debian system. Initial testing in the Debian chroot suggests that this works for simple cases, clang has no problem finding /usr/lib/gcc/x86_64-linux-gnux32/10, and also picks up the right crt*.o files when using -m32 or -m64. Will do more extensive testing.

It does not work for me, unfortunately:

-- Check for working C compiler: /glaubitz/llvm-project/stage1.install/bin/clang - broken
CMake Error at /usr/share/cmake-3.18/Modules/CMakeTestCCompiler.cmake:66 (message):
  The C compiler

    "/glaubitz/llvm-project/stage1.install/bin/clang"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: /glaubitz/llvm-project/build/CMakeFiles/CMakeTmp
    
    Run Build Command(s):/usr/bin/ninja cmTC_52475 && [1/2] Building C object CMakeFiles/cmTC_52475.dir/testCCompiler.c.o
    [2/2] Linking C executable cmTC_52475
    FAILED: cmTC_52475 
    : && /glaubitz/llvm-project/stage1.install/bin/clang   CMakeFiles/cmTC_52475.dir/testCCompiler.c.o -o cmTC_52475   && :
    /usr/bin/x86_64-linux-gnux32-ld: cannot find crt1.o: No such file or directory
    /usr/bin/x86_64-linux-gnux32-ld: cannot find crti.o: No such file or directory
    clang-13: error: linker command failed with exit code 1 (use -v to see invocation)
    ninja: build stopped: subcommand failed.
    
    

  

  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:38 (project)


-- Configuring incomplete, errors occurred!

Stage1 built with:

cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=True -DLLVM_ENABLE_BINDINGS=OFF -DLLVM_LIT_ARGS="-v" -DCMAKE_INSTALL_PREFIX=../stage1.install -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_PARALLEL_LINK_JOBS=4 -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_PROJECTS="clang-tools-extra;llvm;compiler-rt;clang" -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-linux-gnux32  ; ninja -v ; ninja install

Stage 2 configured with:

cmake -G Ninja ../llvm -DCMAKE_C_COMPILER=/glaubitz/llvm-project/stage1.install/bin/clang -DCMAKE_CXX_COMPILER=/glaubitz/llvm-project/stage1.install/bin/clang++ -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=True -DLLVM_LIT_ARGS="-v" -DCMAKE_INSTALL_PREFIX=../stage2.install -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_PARALLEL_LINK_JOBS=4 -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_ENABLE_PROJECTS="clang-tools-extra;llvm;compiler-rt;clang"

I am building with

cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS='clang;libcxx;libcxxabi' -DLLVM_HOST_TRIPLE=x86_64-pc-linux-gnux32 -DBUILD_SHARED_LIBS=ON -DLLVM_LIBDIR_SUFFIX=x32 -DLLVM_ENABLE_RTTI=ON -DLLVM_BUILD_TESTS=ON -DLLVM_TARGETS_TO_BUILD=X86

and testing the resulting clang with simple programs, not yet to build clang again, but the error you are getting suggests that not even simple programs would work. The lack of -DLLVM_HOST_TRIPLE=x86_64-pc-linux-gnux32 in your command line is again suspicious and the fact that I did include that may have avoided the problem you are seeing for me; I will test leaving that out when I finish other tests.

I think the problem is actually the other thing covered before (don't provide un-normalised triples as cmake arguments), though the wrong detection of LLVM_HOST_TRIPLE will cause other issues too. If we would just update config.guess, the default configuration (not specifying either LLVM_HOST_TRIPLE or LLVM_DEFAULT_TARGET_TRIPLE) should work much better; I have created D99625 for that.

I think the problem is actually the other thing covered before (don't provide un-normalised triples as cmake arguments), though the wrong detection of LLVM_HOST_TRIPLE will cause other issues too. If we would just update config.guess, the default configuration (not specifying either LLVM_HOST_TRIPLE or LLVM_DEFAULT_TARGET_TRIPLE) should work much better; I have created D99625 for that.

Updating config.guess fixes the problem for me. Feel free to update the diff here with your suggested patch.

hvdijk commandeered this revision.Mar 31 2021, 12:19 AM
hvdijk edited reviewers, added: glaubitz; removed: hvdijk.

Feel free to update the diff here with your suggested patch.

Alright, thanks. Updating this requires me to 'commandeer' it, doing that now.

hvdijk updated this revision to Diff 334365.Mar 31 2021, 12:21 AM

This updates the diff as described, plus includes test suite changes needed to make check-clang pass. The changes to clang/test/Driver/Inputs/basic_cross_linux_tree/usr are because we now correctly detect that a x86_64 GCC directory that does not include x32 files cannot be used to target x32.

MaskRay added inline comments.Mar 31 2021, 12:28 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

The new x32 does not make sense. Non-x86 targets (--target) should not have to deal with x32 directories.

hvdijk added inline comments.Mar 31 2021, 12:34 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

This is a single string used for all targets and duplicated for all targets (lib64 was already included here too, despite armv6m-none-eabi not using lib64), so I preserved that and updated it for all targets.

hvdijk added inline comments.Mar 31 2021, 12:38 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

Actually, on closer inspection, we really need that here even for ARM: this is not the libdir used by the target, this is the libdir used by the host.

MaskRay added inline comments.Mar 31 2021, 12:50 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

I think we have a problem, then. With --target=armv6m-none-eabi, the host path component lib64 should not appear. Can you investigate why this happens?

My arm-linux-gnu output. Note, if the directories do not exist, some entries may not show up in the output.

% fclang++ --target=arm-linux-gnu a.cc '-###' |& sed -E 's/ "?-[LiI]/\n&/g'
...
 "-L/usr/lib/gcc-cross/arm-linux-gnueabi/10"
 "-L/usr/lib/gcc-cross/arm-linux-gnueabi/10/../../../../arm-linux-gnueabi/lib/../lib"
 "-L/usr/lib/gcc-cross/arm-linux-gnueabi/10/../../../../lib"
 "-L/lib/arm-linux-gnueabi"
 "-L/lib/../lib"
 "-L/usr/lib/arm-linux-gnueabi"
 "-L/usr/lib/../lib"
 "-L/usr/lib/gcc-cross/arm-linux-gnueabi/10/../../../../arm-linux-gnueabi/lib"
 "-L/tmp/RelA/bin/../lib"
 "-L/lib"
 "-L/usr/lib"
hvdijk added inline comments.Mar 31 2021, 1:04 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

I am seeing "ld.lld" "/tmp/baremetal-876ced.o" "-Bstatic" "-L/home/harald/llvm-project/build/libx32/clang/13.0.0/lib/baremetal" [...]. libx32 appears here because I configured with -DLLVM_LIBDIR_SUFFIX=x32. You should see lib64 here if you configure with -DLLVM_LIBDIR_SUFFIX=64.

hvdijk added inline comments.Mar 31 2021, 1:31 AM
clang/test/Driver/baremetal.cpp
37 ↗(On Diff #334365)

The fact that baremetal refers to [host clang]/lib/baremetal comes from BareMetal::getRuntimesDir, https://clang.llvm.org/doxygen/BareMetal_8cpp_source.html#l00169, added by https://reviews.llvm.org/D33259.

https://reviews.llvm.org/D33877 proposed a different approach to adding all possible libdir suffixes, it checked -resource-dir and verified that lib/baremetal was inside the resource dir, but did not update everything. I will take a look later today to see if that approach would work for the rest of the checks too.

hvdijk updated this revision to Diff 334505.Mar 31 2021, 12:02 PM
hvdijk retitled this revision from WIP: [Driver] Fix architecture triplets and search paths for Linux x32 to [Driver] Fix architecture triplets and search paths for Linux x32.

Tests now updated differently, avoiding the need to explicitly list libx32 as an allowed libdir. In clang/test/Preprocessor/iwithprefix.c's case, for the purposes of the test, it is not necessary to look at what appears before /clang/. In the other tests, it is possible to capture the -resource-dir string and use that.

Mostly looks good.

clang/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/x32/crtbegin.o

Worth bumping the version. 4.6 is quite old and as a host compiler llvm-project has stopped supporting it. The distributions having 4.6 are all end-of-life.
Using a new version (matching your reality) can give impression that the user who contributed the original code may still need it for a while (say 5 years).

Currently, support for the x32 ABI is handled as an extension to the x86_64 target only.

As a multilib to the x86_64 target.

However, Debian has a full self-hosting x32 port which is treated as a separate architecture with its own architecture triplets as well as search paths.

I still don't quite understand this. Shouldn't a native x32 port use x86_64-unknown-linux-gnux32? Why does it use the multilib style /x32 suffix?

clang/lib/Driver/ToolChains/Gnu.cpp
2110

Personally I'd defer adding a triplet until it is proven to be used on a system.

This is not free, for every x86-64 user (even if they don't use multilib or x32), their clang driver runs need to stat the directory under lib/gcc or lib/gcc-cross.

hvdijk added a comment.EditedMar 31 2021, 2:18 PM

Mostly looks good.

clang/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/x32/crtbegin.o

Worth bumping the version. 4.6 is quite old and as a host compiler llvm-project has stopped supporting it. The distributions having 4.6 are all end-of-life.
Using a new version (matching your reality) can give impression that the user who contributed the original code may still need it for a while (say 5 years).

Sure, there should be no harm in renaming 4.6.0 to the current version, 10.2.0, will do that and re-test.

I still don't quite understand this. Shouldn't a native x32 port use x86_64-unknown-linux-gnux32? Why does it use the multilib style /x32 suffix?

Apologies for the confusion, that is my fault. @glaubitz opened this change to make things work for Debian, which uses lib/x86_64-linux-gnux32, but I am testing both Debian and non-Debian. Non-Debian uses libx32, similarly to how x86_64-linux-gnu uses lib64 regardless of whether any 32-bit libraries are installed. (Edit: I may have misunderstood your comment. There's also the /x32 subdirectory inside GCC installs, but these are not used for native x32 systems. This is only used for i*86-linux-gnu and x86_64-linux-gnu compilers with multilib support for x32, both on Debian and on non-Debian systems, and is covered by existing tests.)

clang/lib/Driver/ToolChains/Gnu.cpp
2110

For the first and last I know for a fact they are used as the GCC triple; /usr/lib/gcc/x86_64-linux-gnux32 and /usr/lib/gcc/x86_64-pc-linux-gnux32 definitely both exist in the wild. For the middle, x86_64-unknown-linux-gnux32, I do know for a fact this is used as a triple (it is the only valid x32 triple for Rust), but it is possible it is not used as the GCC triple anywhere, so unless someone speaks up that this is already in use somewhere, I will take that one out.

Mostly looks good.

clang/test/Driver/Inputs/basic_cross_linux_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/x32/crtbegin.o

Worth bumping the version. 4.6 is quite old and as a host compiler llvm-project has stopped supporting it. The distributions having 4.6 are all end-of-life.
Using a new version (matching your reality) can give impression that the user who contributed the original code may still need it for a while (say 5 years).

Sure, there should be no harm in renaming 4.6.0 to the current version, 10.2.0, will do that and re-test.

Since I am a big fan of consistency, I would rather leave it as is (4.6) and then bump to 10.2.0 in a follow-up commit.

I still don't quite understand this. Shouldn't a native x32 port use x86_64-unknown-linux-gnux32? Why does it use the multilib style /x32 suffix?

Apologies for the confusion, that is my fault. @glaubitz opened this change to make things work for Debian, which uses lib/x86_64-linux-gnux32, but I am testing both Debian and non-Debian. Non-Debian uses libx32, similarly to how x86_64-linux-gnu uses lib64 regardless of whether any 32-bit libraries are installed. (Edit: I may have misunderstood your comment. There's also the /x32 subdirectory inside GCC installs, but these are not used for native x32 systems. This is only used for i*86-linux-gnu and x86_64-linux-gnu compilers with multilib support for x32, both on Debian and on non-Debian systems, and is covered by existing tests.)

Debian actually has a /libx32 folder, but it contains the dynamic loader only which makes sense because the path to the dynamic loader is baked into the executable if I remember correctly.

glaubitz added inline comments.Mar 31 2021, 3:19 PM
clang/lib/Driver/ToolChains/Gnu.cpp
2110

Isn't Rust going to use x86_64-unknown-linux-gnux32 when invoking the C++ compiler itself? I would prefer keeping it for consistency with x86_64 and to avoid issues with distributions that may use that triplet.

Since I am a big fan of consistency, I would rather leave it as is (4.6) and then bump to 10.2.0 in a follow-up commit.

You are right that including the bump in this commit would either force an inconsistency with basic_linux_tree, multilib_32bit_linux_tree, and multilib_64bit_linux_tree, or include more changes in here that are not related to x32. However, since we have been testing for x32 support against a pretend installation of GCC 4.6, and GCC 4.6 actually never supported x32 (initial support was added in GCC 4.7), leaving it at 4.6.0 means we are testing an impossible scenario. I am aware that we already were doing that before as well, but I do not think that changes much. Personally, I am not very happy with any of the options here.

I am also a fan of consistency, so to me the least bad option seems to be to update all four at the same time, provided this does not result in an excessively large diff. It looks large-ish but not too bad to me; I will include it in the next update so that we know what sort of size we are dealing with. If you and @MaskRay think it is too large I can easily take it out again.

Debian actually has a /libx32 folder, but it contains the dynamic loader only which makes sense because the path to the dynamic loader is baked into the executable if I remember correctly.

Right, it has a /libx32 directory for exactly that reason. /libx32/ld-linux-x32.so.2 only exists as a compatibility symlink though, the dynamic loader is really stored in /lib/x86_64-linux-gnux32.

clang/lib/Driver/ToolChains/Gnu.cpp
2110

Thankfully, Rust does not require external triples to match its own strict naming rules. It does not accept x86_64-linux-gnu or x86_64-pc-linux-gnu as a valid targets either, only x86_64-unknown-linux-gnu, but it still works fine on systems where GCC does use any of the other triple names.

hvdijk updated this revision to Diff 334557.Mar 31 2021, 4:27 PM
hvdijk edited the summary of this revision. (Show Details)

I have also updated the summary to provide a more complete explanation of the changes, and hope the revised summary will answer @MaskRay's questions.

MaskRay accepted this revision.Mar 31 2021, 6:19 PM
This revision is now accepted and ready to land.Mar 31 2021, 6:19 PM

I have also updated the summary to provide a more complete explanation of the changes, and hope the revised summary will answer @MaskRay's questions.

Since I am a big fan of consistency, I would rather leave it as is (4.6) and then bump to 10.2.0 in a follow-up commit.

You are right that including the bump in this commit would either force an inconsistency with basic_linux_tree, multilib_32bit_linux_tree, and multilib_64bit_linux_tree, or include more changes in here that are not related to x32. However, since we have been testing for x32 support against a pretend installation of GCC 4.6, and GCC 4.6 actually never supported x32 (initial support was added in GCC 4.7), leaving it at 4.6.0 means we are testing an impossible scenario. I am aware that we already were doing that before as well, but I do not think that changes much. Personally, I am not very happy with any of the options here.

I was actually wondering which version of GCC introduced x32 support after I posted that comment. You're right then, 4.6.0 makes no sense.

I think, however, we should bump the rest of the paths to 10.2.0 if possible.

I am also a fan of consistency, so to me the least bad option seems to be to update all four at the same time, provided this does not result in an excessively large diff. It looks large-ish but not too bad to me; I will include it in the next update so that we know what sort of size we are dealing with. If you and @MaskRay think it is too large I can easily take it out again.

Debian actually has a /libx32 folder, but it contains the dynamic loader only which makes sense because the path to the dynamic loader is baked into the executable if I remember correctly.

Right, it has a /libx32 directory for exactly that reason. /libx32/ld-linux-x32.so.2 only exists as a compatibility symlink though, the dynamic loader is really stored in /lib/x86_64-linux-gnux32.

Yep, it's just a link - as for the other architectures in Debian as well.

Either way, I'm glad this has finally been approved.

This revision was landed with ongoing or failed builds.Apr 1 2021, 1:50 AM
This revision was automatically updated to reflect the committed changes.
hvdijk added a comment.Apr 1 2021, 1:58 AM

I think, however, we should bump the rest of the paths to 10.2.0 if possible.

I updated all the Linux trees that were on 4.6.0. The only remaining 4.6.0 trees are for Hurd, which seems to me like it was just a coincidence that it was on the same version. There are other Linux trees used for tests as well, but they were already on different versions of GCC so we do not introduce any new inconsistencies by leaving those as they are.

I noticed that I left out one of the 4.6.0 directories by mistake in what I put up for review, that did not affect test results. I included that as obvious in what I pushed.

I think, however, we should bump the rest of the paths to 10.2.0 if possible.

I updated all the Linux trees that were on 4.6.0. The only remaining 4.6.0 trees are for Hurd, which seems to me like it was just a coincidence that it was on the same version. There are other Linux trees used for tests as well, but they were already on different versions of GCC so we do not introduce any new inconsistencies by leaving those as they are.

I noticed that I left out one of the 4.6.0 directories by mistake in what I put up for review, that did not affect test results. I included that as obvious in what I pushed.

OK. Glad this has been fixed, in any case.