Wie funktioniert Multiarch?

1

Ich versuche, ein Multiarch-Rootfs für ein System einzurichten, auf dem beide Endianess auf demselben Kernel ausgeführt werden können. Natürlich kann ich keine Bibliotheken unterschiedlicher Endianness innerhalb desselben Programms mischen. Darüber hinaus ist das Big-Endian-Rootfs mit µClibc und seinem Dynamic Loader verknüpft, während die Little-Endian-Version mit glibc verknüpft ist.

Ich habe keine Ahnung, wie sich die bekannten Systeme von denen trennen, auf denen sowohl i686 als auch amd64 laufen (auch wenn sie selten eine andere Bytereihenfolge verwenden) .

Aber meine Situation sieht in gewisser Hinsicht ähnlich aus ... es bedeutet, dass:

  • Ich kann mit chroot auf ein anderes System wechseln: ( chroot /tmp/rootfs )
  • statisch kompilierte Binärdateien können überall ausgeführt werden;

²

example.c:
int main() {return 200;}

²

localhost# gcc -static -Ofast $HOME/example.c -o $HOME/example
localhost# $HOME/example
localhost# echo $?
200
localhost# mv $HOME/example /tmp/rootfs
localhost# chroot /tmp/rootfs /example
localhost# echo $?
200

Also habe ich die folgenden Pfade zu /etc/ld.so.conf hinzugefügt:

/tmp/rootfs/lib
/tmp/rootfs/usr/lib

und ich habe den Dynamic Loader von den anderen Rootfs kopiert: (µClibc benutze ld-uClibc.so)

localhost# ln /tmp/rootfs/lib/ld-linux.so.2 /lib/
localhost# ln /tmp/rootfs/bin/zsh5 /bin/

ld-linux.so.2 ist eine statische Binärdatei, mit der ich jede dynamisch verknüpfte Bibliothek ausführen kann.

localhost# /lib/ld-linux.so.2 /bin/zsh5
localhost# exit
localhost# 

Es sieht gut aus, aber die Skripte von portage können so nicht funktionieren. Ich kann binfmt nicht verwenden, da dies eine Schleife erzeugen würde, da /lib/ld-linux.so.2 dieselbe Architektur wie das Ziel hat.
Also dachte ich, der Kernel würde den richtigen ELF-Interpreter automatisch finden und verwenden, aber das tut er nicht:

localhost# zsh5
/bin/zsh5: No such file or directory

Ich kann immer noch µClibc-Programme ausführen:

localhost# busybox
BusyBox v1.22.1 (2014-06-11 08:01:31 UTC) multi-call binary.
BusyBox is copyrighted by many authors between 1998-2012.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list[-full]
   or: busybox --install [-s] [DIR]
   or: function [arguments]...

        BusyBox is a multi-call binary that combines many common Unix
        utilities into a single executable.  Most people will create a
        link to busybox for each function they wish to use and BusyBox
        will act like whatever it was invoked as.

Currently defined functions:
        [, [[, acpid, addgroup, adduser, adjtimex, ar, arp, arping, ash, awk, base64, basename, bb, bbconfig, bbsh, blkid, blockdev, brctl, bunzip2, bzcat, bzip2, cal, cat, catv, chat, chattr, chgrp, chmod, chown, chpasswd, chpst,
    chroot, chrt, chvt, cksum, clear, cmp, comm, conspy, cp, cpio, crond, cryptpw, cttyhack, cut, date, dd, deallocvt, delgroup, deluser, depmod, devmem, df, dhcprelay, diff, dirname, dmesg, dnsdomainname, dos2unix, du, dumpkmap,
    dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, ether-wake, expand, expr, false, fbset, fdflush, fdformat, fdisk, fgconsole, fgrep, find, findfs, flash_eraseall, flash_lock, flash_unlock, flashcp, flock, free,
    freeramdisk, fsck, fstrim, fsync, ftpd, fuser, getopt, getty, ginit, grep, groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hostname, httpd, hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, init, insmod, install,
    ionice, iostat, ip, ipaddr, ipcrm, ipcs, iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5, last, less, linux32, linux64, linuxrc, ln, loadfont, loadkmap, login, losetup, lpq, lpr, ls, lsattr, lsmod, lsof,
    lspci, lsusb, lzcat, lzma, lzop, lzopcat, makedevs, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs, mkfifo, mkfs.ext2, mkfs.reiser, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount,
    mountpoint, mpstat, mt, mv, nameif, nanddump, nandwrite, nbd-client, nc, netstat, nice, nmeter, nohup, nslookup, ntpd, openvt, passwd, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir,
    poweroff, powertop, printenv, printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, readahead, readlink, realpath, reboot, renice, reset, resize, rev, rm, rmdir, rmmod, route, rtcwake, runlevel, rx, script, scriptreplay,
    sed, sendmail, seq, setarch, setconsole, setfont, setkeycodes, setlogcons, setserial, setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum, sha512sum, showkey, sleep, softlimit, sort, split, start-stop-daemon, stat, strings, stty,
    su, sum, swapoff, swapon, switch_root, sync, sysctl, tac, tail, tar, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr, traceroute, traceroute6, true, tty, ttysize, tunctl, tune2fs, ubiattach, ubidetach,
    ubimkvol, ubirmvol, ubirsvol, ubiupdatevol, udhcpc, udhcpc6, udhcpd, umount, uname, uncompress, unexpand, uniq, unix2dos, unlzma, unlzop, unxz, unzip, uptime, users, usleep, vconfig, vi, vlock, volname, wall, watch, watchdog,
    wc, wget, which, who, whoami, whois, xargs, xz, xzcat, yes, zcat, zcip

Daher verstehe ich nicht, wie Multiarch-Systeme die richtige Interpreterbibliothek für die richtige Architektur verwenden, da dies nicht funktioniert, und mein Verständnis bleibt an diesem Punkt stecken.

user2284570
quelle
Warten Sie ... wie könnte ein statisch verknüpftes Programm auf zwei verschiedenen Endiannessen ausgeführt werden? Das ergibt keinen Sinn. Der Maschinencode für die beiden Bögen wäre unterschiedlich.
BenjiWiebe
@BenjiWiebe: Ja, das ist irgendwie das Problem. Der Maschinencode ist unterschiedlich (wie bei Itaniums-Prozessoren, die i686-Programme nativ ausführen konnten) (Viele Prozessorarchitekturen können zwei verschiedene Endianness ausführen, solange sich nur eine im Adressraum befindet.) . Es verhält sich wie zwei verschiedene Architekturen, auf denen der Prozessor beide ausführen kann. Ich kann also keine Bibliotheken mischen.
user2284570
Also ... ähm ... der gleiche Maschinencode kann in beiden Modi laufen ???? Sie wollten, dass die statisch verknüpften Programme überall ausgeführt werden.
BenjiWiebe
Auf meinem Multiarch-System (standardmäßig verwende ich Fedora) unterscheidet es sich, mit welchem ​​dynamischen Linker das Programm verknüpft ist, z. Ein 32-Bit-Programm ist mit verknüpft /lib/ld-linux.so.2 gegen ein 64-Bit /lib64/ld-linux-x64-64.so.2.
BenjiWiebe
@BenjiWiebe: No hat es gezeigt: Das Ausführen von statisch verknüpften Programmen ist überall einfach, da keine gemeinsam genutzten Objektdateien erforderlich sind. Ich möchte in der Lage sein, dynamisch verknüpfte Programme von beiden Endianness innerhalb derselben rootfs auszuführen. Die Architektur spielt keine Rolle: Ziel ist es, ein Multiarch-System einzurichten, und auf meinen Plattformen sieht der Prozess ähnlich aus. Ich verstehe den letzten Schritt einfach nicht, und ich verstehe auch nicht, was " system it differs which dynamic linker the program is linked to, e.g. a 32-bit program is linked to /lib/ld-linux.so.2 vs a 64-bit /lib64/ld-linux-x64-64.so.2 "bringt.
user2284570

Antworten:

0

Unter Linux können Sie eine Binärdatei nur mit der Endianess des Kernels ausführen, auf dem sie ausgeführt wird. Wenn Sie eine Armeb-Binärdatei (Big-Endian ARM) ausführen möchten, benötigen Sie einen Armeb-Kernel. Wenn Sie eine Armel-Binärdatei ausführen möchten, benötigen Sie einen Armel-Kernel. Dies gilt für alle CPU-Architekturen, die Big- und Little-Endian-Modi unter Linux unterstützen (ARM, ARM64, ARC, C6x, PowerPC, MIPS, M32R, Microblaze, SH4, Xtensa).

Es gibt zwei Möglichkeiten, dies zu umgehen, aber beide haben auch erhebliche Nachteile:

  1. Du kannst rennen irgendein binär mit QEMU-Benutzer-Emulation . Ein typisches Beispiel hierfür ist das Ausführen einer ARM-Binärdatei auf x86. Sie können jedoch auch eine PowerPC-Little-Endian-Binärdatei auf einem Big-Endian-ARM-Kernel oder einer anderen Kombination ausführen, sofern sowohl der Host als auch das Ziel von qemu unterstützt werden. Einige Dinge (z. B. seltene Gerätetreiber) funktionieren möglicherweise nicht, weil der Emulationscode in qemu fehlt, und im Allgemeinen läuft alles langsam, in der Regel um den Faktor 10 langsamer als die Ausführung der nativen Anweisungen.

  2. Sie können einen KVM-Gast in einer anderen Endianess vom Host ausführen, sofern Sie über Hardware-Support verfügen. Dies funktioniert auf einigen ARM32 (Cortex-A7, A12, A15, A17, aber nicht Cortex-A9 oder älter) sowie auf PowerPC und ARM64. Die Prozesse des Gastes sind für den Host nicht sichtbar oder umgekehrt, und Sie müssen interne Netzwerke und Speicher einrichten, damit der Gast etwas Nützliches tun kann.

Arnd Bergmann
quelle
qemu-user-static mit binfmt. Das ist es, was ich bereits verwende, um die ausführbaren Dateien so auszuführen, als ob sie nativ unterstützt würden. Wie auch immer, ich fand endlich die Lösung und entdeckte, dass sie dank einiger Leute im IRC ein mysteriöses Pfadproblem waren. Ich verstehe nicht, warum dieses Problem aufgetreten ist, aber ich habe es gelöst. Andernfalls können Sie KVM nicht auf mips32r2 verwenden.
user2284570
0

Ok, es schien ein einfaches, hartcodiertes Pfadproblem zu sein.

localhost# readelf -l /bin/zsh5

Elf file type is EXEC (Executable file)
Entry point 0x40f015
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

Hinzufügen dieser Bibliothek an diesem Pfad und ld-2.19.so im LD_LIBRARY_PATH mein problem gelöst.

Es ist also wahrscheinlich das erste System, das amd64 und mips genauso ausführen kann wie i686 :).

user2284570
quelle