Como funciona o multiarch?

1

Estou tentando configurar um rootfs multiarch para um sistema que pode executar ambos os endianess do mesmo kernel. É claro que não consigo misturar bibliotecas de diferente endianness dentro do mesmo programa. Além disso, o big endian rootfs está ligado para usar µClibc com seu carregador dinâmico, enquanto a versão little endian está vinculada à glibc.

Eu não tenho idéia de como a divisão conhecida de sistemas que executam o i686 e o amd64 (mesmo eles raramente usam ordem de byte diferente) .

Mas minha situação parece semelhante em alguns aspectos ... significa que:

  • Eu posso mudar para um sistema diferente usando o chroot: ( chroot /tmp/rootfs )
  • binários estaticamente compilados podem ser executados em qualquer lugar;

²

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

Então eu adicionei os seguintes caminhos para /etc/ld.so.conf:

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

e eu copiei o carregador dinâmico dos outros rootfs: (µClibc use ld-uClibc.so)

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

O ld-linux.so.2 é um binário estático, portanto, posso executar qualquer biblioteca vinculada dinamicamente com ele.

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

Parece legal, mas os scripts do portage não poderão funcionar dessa maneira. Eu não posso usar o binfmt, pois ele criaria um loop porque o /lib/ld-linux.so.2 tem a mesma arquitetura que o destino.
Então eu pensei que o kernel encontraria e usaria o interpretador ELF correto automaticamente, mas isso não acontece:

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

Ainda sou capaz de executar executáveis µClibc:

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

Então, eu não entendo como os sistemas multiarch usam a biblioteca de intérpretes certa para a arquitetura certa, uma vez que isso não funciona, e meu entendimento está preso nesse ponto.

    
por user2284570 15.07.2014 / 03:15

2 respostas

0

No Linux, você só pode executar um binário com o mesmo endianess que o kernel em que está sendo executado. Se você quer rodar um binário armeb (big-endian ARM), você precisa ter um kernel armeb e se você quer rodar um binário de armel, você precisa ter um kernel armel. Isso vale para todas as arquiteturas de CPU que suportam modos big e little-endian no Linux (ARM, ARM64, ARC, C6, PowerPC, MIPS, m32r, microblaze, SH4, xtensa).

Existem duas maneiras de contornar isso, mas ambas também têm desvantagens significativas:

  1. Você pode executar qualquer binário usando emulação do qemu-user . Um exemplo típico disso é executar um binário ARM em x86, mas você também pode executar um binário Power-little endian em um kernel ARM big-endian ou qualquer outra combinação, desde que o host e o destino sejam suportados pelo qemu. Algumas coisas (por exemplo, drivers de dispositivo raros) podem não funcionar devido à falta de código de emulação no qemu e, em geral, tudo será executado lentamente, normalmente um fator de 10 mais lento do que executar as instruções nativas.

  2. Você pode executar um guest KVM em diferentes finalidades do host, desde que tenha suporte de hardware. Isso funciona em alguns ARM32 (Cortex-A7, A12, A15, A17, mas não Cortex-A9 ou mais antigos), bem como PowerPC e ARM64. Os processos do convidado não são visíveis para o host ou vice-versa, e você precisa configurar a rede interna e o armazenamento para que o convidado faça qualquer coisa útil.

por 15.07.2014 / 08:48
0

Ok, parece que era um problema simples de caminho codificado.

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]

adicionando esta biblioteca nesse caminho e ld-2.19.so em LD_LIBRARY_PATH resolveu meu problema.

Portanto, é provavelmente o primeiro sistema que é capaz de rodar amd64 e mips da mesma maneira que pode rodar i686:).

    
por 25.07.2014 / 15:35

Tags