autoPatchelfHook 32-bit executable on 64 bit system

I’m trying to write a derivation for MRIcro on Linux.

It distributes a 32-bit executable which is supposed to run on 64 bit architectures.

Applying the usual autoPatchelfHook pattern results in the executable being ignored by patchelf, presumably because a 64-bit one is being applied to a 32-bit resource.

How I get around this obstacle?

Use pkgsi686Linux which will give you a 32bit stdenv and libraries the executable can actually be linked against.

You mean something like this:

{ pkgs ,
  lib,
  fetchurl,
  autoPatchelfHook
}:

pkgs.pkgsi686Linux.stdenv.mkDerivation (finalAttrs: {
  pname = "mricro";
  version = "1.39-build-3";

  src = fetchurl {
    url = "https://people.cas.sc.edu/rorden/mricro/mricrox.tar.gz"; # TODO find URL to specific version.
    sha256 = "sha256-RHLM6dk7dLMD98hLMAo14NiqnMXc1ERMo701vFfN1hg=";
  };

  nativeBuildInputs = [
    autoPatchelfHook
  ];

  sourceRoot = "."; # Because the tarball contains the binaries at top-level

  installPhase = ''
     install -m 555 -D ./startmricro* -t $out/bin
  '';
})

?

That seems to have done the trick in terms of patching the 32-bit binary instead of ignoring it. (Now I get segfaults …)

Yes although I would recommend using pkgsi6868Linux.callPackage to avoid 64-bit inputs to leak into the build, i. e.

{ pkgs ? import <nixpkgs> {} }:

let
  f = { stdenv, autoPatchelfHook, fetchurl }:
    stdenv.mkDerivation (finalAttrs: { /* … */ });
in

pkgs.pkgsi686Linux.callPackage f { }

Segfault will probably require looking at gdb/valgrind, seems possible that it is some linking issue / missing libs or the like.

Not sure how much use gdb/valgrind can be, given that the binary I’ve got to work with is stripped. It’s been a while since I’ve used either of these, and never without debugging symbols.

It’s quite likely that missing libs is the problem. The contents of result/bin/startmricro64 are

#!/nix/store/bsgjbpzxanp5l2q5f6mbs6fk11yzh0c5-bash-5.1-p16/bin/bash
export GCONV_PATH=/usr/lib32/gconv
startmricro

so it looks like telling it about the location of a 32 bit gconv, might help. Not sure how to go about doing that.

You can add gconv to runtimeDependencies – maybe it wants to link against it. Otherwise substitute the GCONV_PATH variable with the correct path in the script.

Not entirely sure which gconv this is, as there is nothing by that name in nixpkgs. Assuming it’s what comes with glibc, then patching it with sed to make it look like this

#!/nix/store/bsgjbpzxanp5l2q5f6mbs6fk11yzh0c5-bash-5.1-p16/bin/bash
export GCONV_PATH=/nix/store/hs6k3j5cca3nslxfmb8xkqbknkkmkbf5-glibc-2.34-210/lib/gconv
startmricro

and adding glibc to runtimeDependencies, doesn’t seem to improve matters.

[Not sure whether it’s meaningful, but I’ve even tried adding "${glibc}/lib/gconv" to runtimeDependencies, to no avail.]

That seems good.

This is unnecessary / a no-op, autoPatchelfHook will already know about glibc from stdenv.

Yeah seems like gconv is opened from a path with dlopen and not linked against per se.