Skip to content

linux-i386 support #3808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 1, 2019
Merged

linux-i386 support #3808

merged 4 commits into from
Dec 1, 2019

Conversation

LemonBoy
Copy link
Contributor

I didn't add a socketcall stub for sendmmsg because it's horribly messy and lost all the motivation halfway trough.

Enjoy 🎉

@andrewrk
Copy link
Member

andrewrk commented Nov 30, 2019

TODO implement target_dynamic_linker for mips

That one should hopefully be straightforward:

zig/src/target.cpp

Lines 1307 to 1311 in 85e1e3b

case ZigLLVM_mips:
case ZigLLVM_mipsel:
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
zig_panic("TODO implement target_dynamic_linker for mips");

Here's the relevant code from clang:

std::string Linux::getDynamicLinker(const ArgList &Args) const {
  const llvm::Triple::ArchType Arch = getArch();
  const llvm::Triple &Triple = getTriple();

  const Distro Distro(getDriver().getVFS());

  if (Triple.isAndroid())
    return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";

  if (Triple.isMusl()) {
    std::string ArchName;
    bool IsArm = false;

    switch (Arch) {
    case llvm::Triple::arm:
    case llvm::Triple::thumb:
      ArchName = "arm";
      IsArm = true;
      break;
    case llvm::Triple::armeb:
    case llvm::Triple::thumbeb:
      ArchName = "armeb";
      IsArm = true;
      break;
    default:
      ArchName = Triple.getArchName().str();
    }
    if (IsArm &&
        (Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
         tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard))
      ArchName += "hf";

    return "/lib/ld-musl-" + ArchName + ".so.1";
  }

  std::string LibDir;
  std::string Loader;

  switch (Arch) {
  default:
    llvm_unreachable("unsupported architecture");

  case llvm::Triple::aarch64:
    LibDir = "lib";
    Loader = "ld-linux-aarch64.so.1";
    break;
  case llvm::Triple::aarch64_be:
    LibDir = "lib";
    Loader = "ld-linux-aarch64_be.so.1";
    break;
  case llvm::Triple::arm:
  case llvm::Triple::thumb:
  case llvm::Triple::armeb:
  case llvm::Triple::thumbeb: {
    const bool HF =
        Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
        tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard;

    LibDir = "lib";
    Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
    break;
  }
  case llvm::Triple::mips:
  case llvm::Triple::mipsel:
  case llvm::Triple::mips64:
  case llvm::Triple::mips64el: {
    bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple);

    LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple);

    if (tools::mips::isUCLibc(Args))
      Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
    else if (!Triple.hasEnvironment() &&
             Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies)
      Loader =
          Triple.isLittleEndian() ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
    else
      Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";

    break;
  }
  case llvm::Triple::ppc:
    LibDir = "lib";
    Loader = "ld.so.1";
    break;
  case llvm::Triple::ppc64:
    LibDir = "lib64";
    Loader =
        (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1";
    break;
  case llvm::Triple::ppc64le:
    LibDir = "lib64";
    Loader =
        (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2";
    break;
  case llvm::Triple::riscv32: {
    StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
    LibDir = "lib";
    Loader = ("ld-linux-riscv32-" + ABIName + ".so.1").str();
    break;
  }
  case llvm::Triple::riscv64: {
    StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
    LibDir = "lib";
    Loader = ("ld-linux-riscv64-" + ABIName + ".so.1").str();
    break;
  }
  case llvm::Triple::sparc:
  case llvm::Triple::sparcel:
    LibDir = "lib";
    Loader = "ld-linux.so.2";
    break;
  case llvm::Triple::sparcv9:
    LibDir = "lib64";
    Loader = "ld-linux.so.2";
    break;
  case llvm::Triple::systemz:
    LibDir = "lib";
    Loader = "ld64.so.1";
    break;
  case llvm::Triple::x86:
    LibDir = "lib";
    Loader = "ld-linux.so.2";
    break;
  case llvm::Triple::x86_64: {
    bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32;

    LibDir = X32 ? "libx32" : "lib64";
    Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2";
    break;
  }
  }

  if (Distro == Distro::Exherbo &&
      (Triple.getVendor() == llvm::Triple::UnknownVendor ||
       Triple.getVendor() == llvm::Triple::PC))
    return "/usr/" + Triple.str() + "/lib/" + Loader;
  return "/" + LibDir + "/" + Loader;
}

@andrewrk
Copy link
Member

andrewrk commented Nov 30, 2019

Even if i386-linux-gnu and the mips targets couldn't be enabled, there are still 2 new targets gaining test coverage here, which is still pretty great

@andrewrk
Copy link
Member

Also I went ahead and filed https://todo.sr.ht/~sircmpwn/builds.sr.ht/252

@daurnimator daurnimator added arch-x86 32-bit x86 arch-mips 32-bit and 64-bit MIPS labels Nov 30, 2019
@daurnimator
Copy link
Contributor

daurnimator commented Nov 30, 2019

Linux (since 4.2) has non-socketcall syscalls. e.g. recvmsg is syscall 372

https://lore.kernel.org/lkml/cb5138299d37d5800e2d135b01a7667fa6115854.1436912629.git.luto@kernel.org/

For 32-bit programs, we're stuck offering the socketcall syscall, but it would be nice to expose the direct calls as well. This will enable seccomp to filter socket calls (for new userspace only, but that's fine for some applications) and it will provide a tiny performance boost.

@andrewrk
Copy link
Member

andrewrk commented Nov 30, 2019

Our current minimum Linux is 3.16. But it's planned to have #1907, so both impls would be OK. Also in a separate issue, anyone is free to make a case for raising the minimum supported version, if the vast majority of Linux distributions are on a newer kernel. I believe the rather popular CentOS still has an active LTS on 3.16.

@andrewrk
Copy link
Member

I'll have a look at that windows failure locally. I suspect we may be hitting memory limits (see #471) on the Windows CI.

@andrewrk andrewrk merged commit 951dc45 into ziglang:master Dec 1, 2019
@LemonBoy
Copy link
Contributor Author

LemonBoy commented Dec 1, 2019

Even if i386-linux-gnu and the mips targets couldn't be enabled, there are still 2 new targets gaining test coverage here, which is still pretty great

The work required to get i386+glibc to work outweighs any possible advantage:

  • You'd have to provide the get_pc_thunk stubs [1] and find out why clang doesn't generate them (afaics they use a slightly different strategy to get the current IP that requires no stubs)
  • Change the stdlib to use the 64-bit version of all the I/O functions (open64, lseek64, fstat64...)
  • Try to understand why glibc exports lseek64 with version 2.2 on every architecture but i386, where the only lseek64 symbol has version 2.1. This makes the change outlined above non-trivial.

The mips+glibc target requires some glibc build-system debugging, a dull and boring task that excites no one.

Linux (since 4.2) has non-socketcall syscalls. e.g. recvmsg is syscall 372

Backwards compatibility with 3.6 (and possibly older kernels) requires those calls to go through socketcall.

[1] https://raw.githubusercontent.com/gcc-mirror/gcc/master/gcc/config/i386/i386.c

@daurnimator
Copy link
Contributor

daurnimator commented Dec 1, 2019

  • You'd have to provide the get_pc_thunk stubs [1] and find out why clang doesn't generate them (afaics they use a slightly different strategy to get the current IP that requires no stubs)

If clang doesn't need them... why do we? Is this a libgcc thing? or a glibc thing?

Change the stdlib to use the 64-bit version of all the I/O functions (open64, lseek64, fstat64...)

We'll need to do that anyway at some point right?

Backwards compatibility with 3.6 (and possibly older kernels) requires those calls to go through socketcall.

Yeah fair enough: that needs to wait for #1907

@LemonBoy
Copy link
Contributor Author

LemonBoy commented Dec 1, 2019

If clang doesn't need them... why do we? Is this a libgcc thing? or a glibc thing?

Good question, the glibc sources Zig ships with include a definition of those stubs in the .gnu.linkonce section to avoid code bloat. Nowadays the very same is achieved by a comdat section so lld helpfully discards those as the compiler is expected to generate them. Lo and behold, we end up with a relocation against a symbol that's been discarded and LLD is very sad about that.

The real question is whether glibc can be successfully built with clang or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-mips 32-bit and 64-bit MIPS arch-x86 32-bit x86 os-linux
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants