Les binaires sont-ils portables sur différentes architectures CPU?

16

Mon objectif est de pouvoir développer pour Linux embarqué. J'ai de l'expérience sur les systèmes embarqués bare-metal utilisant ARM.

J'ai quelques questions générales sur le développement pour différentes cibles de CPU. Mes questions sont les suivantes:

  1. Si j'ai une application compilée pour s'exécuter sur une « cible x86, linux OS version xyz », puis-je simplement exécuter le même binaire compilé sur un autre système « ARM target, linux OS version xyz »?

  2. Si ce n'est pas vrai, le seul moyen est d'obtenir le code source de l'application pour reconstruire / recompiler en utilisant la chaîne d'outils appropriée 'par exemple, arm-linux-gnueabi'?

  3. De même, si j'ai un module de noyau chargeable (pilote de périphérique) qui fonctionne sur une « cible x86, linux OS version xyz », puis-je simplement charger / utiliser le même .ko compilé sur un autre système « cible ARM, linux OS version xyz » ?

  4. Si ce n'est pas vrai, le seul moyen est d'obtenir le code source du pilote pour reconstruire / recompiler en utilisant la chaîne d'outils appropriée 'par exemple, arm-linux-gnueabi'?

mousser
la source
27
non, oui, non, oui.
Hobbs
7
Cela aide à réaliser que nous n'avons pas de cible AMD et Intel, juste une seule cible x86 pour les deux. En effet, Intel et AMD sont suffisamment compatibles. Il devient alors évident que la cible ARM existe pour une raison spécifique, à savoir parce que les processeurs ARM ne sont pas compatibles avec Intel / AMD / x86.
MSalters
1
Non, sauf s'il s'agit d'un bytecode conçu pour s'exécuter sur un environnement d'exécution portable comme Java Runtime. Si vous écrivez du code pour une utilisation intégrée, votre code reposera probablement sur des optimisations ou des fonctionnalités spécifiques au processeur de bas niveau et sera très difficile à porter, nécessitant plus qu'une simple compilation pour la plate-forme cible (par exemple, les modifications du code d'assemblage, éventuellement la réécriture plusieurs modules ou l'ensemble du programme).
bwDraco
1
@MSalters: En fait, nous avons une cible AMD: amd64 qui est souvent étiquetée x86-64 (tandis que x86 est généralement un nouvel étiquetage de i386). Heureusement, Intel a copié (et développé plus tard) l'architecture AMD pour que tout x86 64 bits puisse exécuter des binaires amd64.
slebetman

Réponses:

42

Non. Les binaires doivent être (re) compilés pour l'architecture cible, et Linux n'offre rien de tel que les gros binaires prêts à l'emploi. La raison en est que le code est compilé en code machine pour une architecture spécifique et que le code machine est très différent entre la plupart des familles de processeurs (ARM et x86 par exemple sont très différents).

EDIT: il convient de noter que certaines architectures offrent des niveaux de compatibilité descendante (et encore plus rare, la compatibilité avec d'autres architectures); sur les processeurs 64 bits, il est courant d'avoir une compatibilité descendante avec les éditions 32 bits (mais rappelez-vous: vos bibliothèques dépendantes doivent également être 32 bits, y compris votre bibliothèque standard C, sauf si vous établissez une liaison statique ). Il convient également de mentionner Itanium , où il était possible d'exécuter du code x86 (32 bits uniquement), quoique très lentement; la faible vitesse d'exécution du code x86 était au moins en partie la raison pour laquelle il n'a pas été très réussi sur le marché.

Gardez à l'esprit que vous ne pouvez toujours pas utiliser de binaires compilés avec des instructions plus récentes sur des CPU plus anciens, même dans les modes de compatibilité (par exemple, vous ne pouvez pas utiliser AVX dans un binaire 32 bits sur les processeurs Nehalem x86 ; le CPU ne le prend tout simplement pas en charge.

Notez que les modules du noyau doivent être compilés pour l'architecture appropriée; en outre, les modules de noyau 32 bits ne fonctionneront pas sur les noyaux 64 bits ou vice versa.

Pour plus d'informations sur la compilation croisée des fichiers binaires (vous n'avez donc pas besoin d'avoir une chaîne d'outils sur le périphérique ARM cible), voir la réponse complète de grochmal ci-dessous.

Elizafox
la source
1
Il peut être utile de clarifier toute compatibilité (ou absence de compatibilité) entre x86 et x64, étant donné que certains binaires x86 peuvent fonctionner sur des plates-formes x64. (Je ne suis pas sûr que ce soit le cas sur Linux, mais c'est sur Windows, par exemple.)
jpmc26
4
@ jpmc26 c'est possible sous Linux; mais vous devrez peut-être d'abord installer des bibliothèques de compatibilité. La prise en charge x86 est une partie non facultative des installations Win64. Sous Linux, c'est facultatif; et parce que le monde Linux est bien plus avancé dans la mise à disposition de versions 64 bits de tout ce qui est disponible, certaines distributions ne sont pas par défaut installées (toutes?) des bibliothèques 32 bits. (Je ne sais pas à quel point c'est courant; mais j'ai déjà vu quelques questions à ce sujet de la part de personnes gérant des distributions traditionnelles.)
Dan is Fiddling by Firelight
@ jpmc26 J'ai mis à jour ma réponse avec vos notes; J'ai pensé à le mentionner mais je n'ai pas voulu compliquer la réponse.
Elizafox
16

Elizabeth Myers a raison, chaque architecture nécessite un binaire compilé pour l'architecture en question. Pour créer des binaires pour une architecture différente de celle sur laquelle votre système fonctionne, vous avez besoin d'un fichier cross-compiler.


Dans la plupart des cas, vous devez compiler un compilateur croisé. Je n'ai qu'une expérience avec gcc(mais je crois que llvm, et d'autres compilateurs, ont des paramètres similaires). Un gcccompilateur croisé est obtenu en ajoutant --targetà la configuration:

./configure --build=i686-arch-linux-gnu --target=arm-none-linux-gnueabi

Vous devez compiler gcc, glibcet binutilsavec ces paramètres (et fournir les en-têtes du noyau du noyau sur la machine cible).

En pratique, cela est considérablement plus compliqué et différentes erreurs de construction apparaissent sur différents systèmes.

Il existe plusieurs guides sur la façon de compiler la chaîne d'outils GNU mais je recommanderai Linux From Scratch , qui est continuellement maintenu et fait un très bon travail pour expliquer ce que font les commandes présentées.

Une autre option est une compilation bootstrap d'un compilateur croisé. Merci à la difficulté de compiler des compilateurs croisés pour différentes architectures sur différentes architecturescrosstool-ng été créé. Il donne un bootstrap sur la chaîne d'outils nécessaire pour construire un compilateur croisé.

crosstool-ng prend en charge plusieurs triplets cibles sur différentes architectures, il s'agit essentiellement d'un bootstrap où les gens consacrent leur temps à résoudre les problèmes survenant lors de la compilation d'une chaîne d'outils de compilation croisée.


Plusieurs distributions fournissent des compilateurs croisés sous forme de packages:

En d'autres termes, vérifiez ce que votre distribution propose en termes de compilateurs croisés. Si votre distribution n'a pas de compilateur croisé pour vos besoins, vous pouvez toujours le compiler vous-même.

Les références:


Note sur les modules du noyau

Si vous compilez votre compilateur croisé à la main, vous avez tout ce dont vous avez besoin pour compiler les modules du noyau. C'est parce que vous avez besoin des en-têtes du noyau pour compilerglibc .

Mais, si vous utilisez un compilateur croisé fourni par votre distribution, vous aurez besoin des en-têtes de noyau du noyau qui s'exécute sur la machine cible.

grochmal
la source
FWIW Fedora comprend également des compilateurs croisés.
mattdm
@mattdm - merci, la réponse a été modifiée, je crois avoir lié la bonne partie du wiki fedora.
grochmal
2
Un moyen plus simple que Linux From Scratch pour obtenir un Linux et une chaîne d'outils pour une autre architecture est crosstool-ng. Vous voudrez peut-être ajouter cela à la liste. De plus, la configuration et la compilation manuelle d'une chaîne d'outils croisés GNU pour une architecture donnée est incroyablement impliquée et beaucoup plus fastidieuse que de simples --targetindicateurs. Je soupçonne que cela fait partie de la raison pour laquelle le LLVM gagne en popularité; Il est conçu de telle manière que vous n'avez pas besoin d'une reconstruction pour cibler une autre architecture - à la place, vous pouvez cibler plusieurs backends en utilisant les mêmes bibliothèques de frontend et d'optimiseur.
Iwillnotexist Idonotexist
@IwillnotexistIdonotexist - merci, j'ai encore peaufiné la réponse. Je n'ai jamais entendu parler de crosstool-ng auparavant, et cela semble très utile. Votre commentaire m'a en fait été très utile.
grochmal
9

Notez qu'en dernier recours (c'est-à-dire lorsque vous n'avez pas le code source), vous pouvez exécuter des binaires sur une architecture différente en utilisant des émulateurs comme qemu, dosboxou exagear. Certains émulateurs sont conçus pour émuler des systèmes autres que Linux (par exempledosbox sont conçus pour exécuter des programmes MS-DOS, et il existe de nombreux émulateurs pour les consoles de jeux populaires). L'émulation a un surdébit de performances significatif: les programmes émulés s'exécutent 2 à 10 fois plus lentement que leurs homologues natifs.

Si vous devez exécuter des modules du noyau sur un processeur non natif, vous devrez émuler l'ensemble du système d'exploitation, y compris le noyau pour la même architecture. AFAIK il est impossible d'exécuter du code étranger dans le noyau Linux.

Dmitry Grigoryev
la source
3
La pénalité de vitesse pour l'émulation est souvent encore supérieure à 10x, mais si l'on essaie d'exécuter du code écrit pour une machine 16Mhz sur une machine 4GHz (une différence de vitesse de 250: 1), un émulateur qui a une pénalité de vitesse de 50: 1 peut toujours exécuter le code beaucoup plus rapidement qu'il ne l'aurait fait sur la plate-forme d'origine.
supercat
7

Non seulement les binaires ne sont pas portables entre x86 et ARM, il existe différentes versions d'ARM .

Celui que vous rencontrerez probablement dans la pratique est ARMv6 vs ARMv7. Raspberry Pi 1 est ARMv6, les versions ultérieures sont ARMv7. Il est donc possible de compiler du code sur les derniers qui ne fonctionnent pas sur le Pi 1.

Heureusement, l'un des avantages de l'open source et des logiciels gratuits est d'avoir la source afin que vous puissiez la reconstruire sur n'importe quelle architecture. Bien que cela puisse nécessiter un certain travail.

(La version ARM prête à confusion, mais s'il y a un V avant le nombre, il s'agit de l'architecture du jeu d'instructions (ISA). S'il n'y en a pas, c'est un numéro de modèle comme "Cortex M0" ou "ARM926EJS". Les numéros de modèle n'ont rien à faire avec les numéros ISA.)

pjc50
la source
2
... et puis il y a même des sous-saveurs différentes pour la même saveur ARM, et même des ABI différents pour le même matériel exact (je pense à tout le désordre ARM soft / softfp / hard flottant).
Matteo Italia
1
@MatteoItalia Ugh. Les multiples ABI étaient un snafu, un remède à quelque chose de pire que la maladie. Certains ARM n'avaient aucun registre VFP ou NEON, certains en avaient 16, certains 32. Sur Cortex-A8 et plus tôt, le moteur NEON exécutait une douzaine de CC derrière le reste du cœur, donc le transfert d'une sortie vectorielle vers un GPR coûtait un lot. ARM est parvenu à faire ce qu'il fallait: rendre obligatoire un large sous-ensemble commun de fonctionnalités.
Iwillnotexist Idonotexist
7

Vous devez toujours cibler une plate - forme. Dans le cas le plus simple, le CPU cible exécute directement le code compilé dans le binaire (cela correspond grosso modo aux exécutables COM de MS DOS). Prenons deux plates-formes différentes que je viens d'inventer - Armistice et Intellio. Dans les deux cas, nous aurons un simple programme hello world qui affiche 42 à l'écran. Je suppose également que vous utilisez un langage multi-plateforme d'une manière indépendante de la plate-forme, donc le code source est le même pour les deux:

Print(42)

Sur Armistice, vous disposez d'un pilote de périphérique simple qui prend en charge l'impression des numéros, donc tout ce que vous avez à faire est de sortir sur un port. Dans notre langage d'assemblage portable, cela correspondrait à quelque chose comme ceci:

out 1234h, 42

Cependant, ou le système Intellio n'a rien de tel, il doit donc passer par d'autres couches:

mov a, 10h
mov c, 42
int 13h

Oups, nous avons déjà une différence significative entre les deux, avant même de passer au code machine! Cela correspondrait à peu près au genre de différence que vous avez entre Linux et MS DOS, ou un PC IBM et une X-Box (même si les deux peuvent utiliser le même processeur).

Mais c'est à cela que servent les systèmes d'exploitation. Supposons que nous ayons un HAL qui s'assure que toutes les différentes configurations matérielles sont gérées de la même manière sur la couche application - en gros, nous utiliserons l'approche Intellio même sur l'Armistice, et notre code "d'assemblage portable" finira par être le même. Il est utilisé à la fois par les systèmes modernes de type Unix et Windows, souvent même dans des scénarios intégrés. Bon - maintenant, nous pouvons avoir le même code d'assemblage vraiment portable sur Armistice et Intellio. Mais qu'en est-il des binaires?

Comme nous l'avons supposé, le CPU doit exécuter le binaire directement. Regardons la première ligne de notre code mov a, 10h, sur Intellio:

20 10

Oh. Il s'avère que mov a, constantc'est si populaire qu'il a sa propre instruction, avec son propre opcode. Comment l'Armistice gère-t-il cela?

36 01 00 10

Hmm. Il y a l'opcode pourmov.reg.imm , nous avons donc besoin d'un autre argument pour sélectionner le registre auquel nous assignons. Et la constante est toujours un mot de 2 octets, en notation big-endian - c'est ainsi que l'Armistice a été conçu, en fait, toutes les instructions de l'Armistice ont une longueur de 4 octets, sans exception.

Imaginez maintenant exécuter le binaire d'Intellio sur Armistice: le CPU commence à décoder l'instruction, trouve l'opcode 20h. À l'armistice, cela correspond, disons, à l' and.imm.reginstruction. Il essaie de lire la constante de mot de 2 octets (qui lit 10XX, déjà un problème), puis le numéro de registre (un autreXX ). Nous exécutons la mauvaise instruction, avec les mauvais arguments. Et pire encore, la prochaine instruction sera complètement fausse, car nous avons en fait mangé une autre instruction, pensant qu'il s'agissait de données.

L'application n'a aucune chance de fonctionner, et elle se bloquera ou se bloquera presque immédiatement.

Maintenant, cela ne signifie pas qu'un exécutable doit toujours dire qu'il fonctionne sur Intellio ou Armistice. Il vous suffit de définir une plate-forme indépendante du processeur (comme bashsur Unix), ou à la fois du processeur et du système d'exploitation (comme Java ou .NET, et même aujourd'hui JavaScript, en quelque sorte). Dans ce cas, l'application peut utiliser un exécutable pour tous les différents CPU et OS, tandis qu'il y a une application ou un service sur le système cible (qui cible directement le CPU et / ou OS correct) qui traduit le code indépendant de la plateforme en quelque chose que Le CPU peut réellement s'exécuter. Cela peut ou non avoir un impact sur les performances, les coûts ou les capacités.

Les CPU viennent généralement en famille. Par exemple, tous les CPU de la famille x86 ont un ensemble commun d'instructions qui sont encodées exactement de la même manière, donc chaque CPU x86 peut exécuter chaque programme x86, tant qu'il n'essaie pas d'utiliser des extensions (par exemple, opérations en virgule flottante ou opérations vectorielles). Sur x86, les exemples les plus courants aujourd'hui sont Intel et AMD, bien sûr. Atmel est une entreprise bien connue qui conçoit des processeurs de la famille ARM, assez populaire pour les appareils embarqués. Apple a également ses propres processeurs ARM, par exemple.

Mais ARM est totalement incompatible avec x86 - ils ont des exigences de conception très différentes et ont très peu en commun. Les instructions ont des opcodes entièrement différents, elles sont décodées d'une manière différente, les adresses mémoire sont traitées différemment ... Il pourrait être possible de créer un binaire qui s'exécute à la fois sur un processeur x86 et un processeur ARM, en utilisant des opérations sûres pour faire la distinction entre les deux et passer à deux ensembles d'instructions complètement différents, mais cela signifie toujours que vous avez des instructions distinctes pour les deux versions, avec juste un bootstrapper qui sélectionne le bon ensemble au moment de l'exécution.

Luaan
la source
3

Il est possible de reformuler cette question dans un environnement qui pourrait être plus familier. Par analogie:

"J'ai un programme Ruby que je veux exécuter, mais ma plate-forme n'a qu'un interprète Python. Puis-je utiliser l'interpréteur Python pour exécuter mon programme Ruby, ou dois-je réécrire mon programme en Python?"

Une architecture de jeu d'instructions ("cible") est un langage - un "langage machine" - et différents CPU implémentent différents langages. Donc, demander à un processeur ARM d'exécuter un binaire Intel revient à essayer d'exécuter un programme Ruby à l'aide d'un interpréteur Python.

Jander
la source
2

gcc utilise les termes «architecture» pour désigner le «jeu d'instructions» d'un processeur spécifique, et «cible» couvre la combinaison du processeur et de l'architecture, ainsi que d'autres variables telles que ABI, libc, endian-ness et plus (incluant éventuellement le "métal nu"). Un compilateur typique a un ensemble limité de combinaisons cibles (probablement un ABI, une famille de CPU, mais peut-être à la fois 32 et 64 bits). Un compilateur croisé signifie généralement soit un compilateur avec une cible autre que le système sur lequel il s'exécute, soit un compilateur avec plusieurs cibles ou ABI (voir aussi ceci ).

Les binaires sont-ils portables sur différentes architectures CPU?

En général, non. Un binaire en termes conventionnels est un code objet natif pour un CPU ou une famille de CPU particulier. Mais, il existe plusieurs cas où ils peuvent être modérément à hautement portables:

  • une architecture est un surensemble d'une autre (généralement les binaires x86 ciblent i386 ou i686 plutôt que le dernier et le meilleur x86, par exemple -march=core2)
  • une architecture fournit une émulation ou une traduction native d'une autre (vous avez peut-être entendu parler de Crusoe ), ou fournit des co-processeurs compatibles (par exemple PS2 )
  • le système d'exploitation et le support d'exécution prennent en charge plusieurs architectures (par exemple, la possibilité d'exécuter des binaires x86 32 bits sur x86_64), ou de rendre la machine virtuelle / JIT transparente (Android utilisant Dalvik ou ART )
  • il existe un support pour les binaires "fat" qui contiennent essentiellement du code en double pour chaque architecture prise en charge

Si vous parvenez d'une manière ou d'une autre à résoudre ce problème, l' autre problème binaire portable des innombrables versions de bibliothèque (glibc que je vous regarde) se présentera alors. (La plupart des systèmes embarqués vous évitent au moins ce problème particulier.)

Si vous ne l'avez pas déjà fait, c'est le bon moment pour courir gcc -dumpspecset gcc --target-helpvoir ce que vous affrontez.

Les gros fichiers binaires ont divers inconvénients , mais ont encore des utilisations potentielles ( EFI ).

Il y a cependant deux autres considérations qui manquent dans les autres réponses: ELF et l'interpréteur ELF, et le support du noyau Linux pour les formats binaires arbitraires . Je n'entrerai pas dans les détails sur les binaires ou le bytecode pour les processeurs non réels ici, bien qu'il soit possible de les traiter comme "natifs" et d'exécuter des binaires de bytecode Java ou Python compilés , ces binaires sont indépendants de l'architecture matérielle (mais dépendent à la place sur la version de VM appropriée, qui exécute finalement un binaire natif).

Tout système Linux contemporain utilisera des binaires ELF (détails techniques dans ce PDF ), dans le cas des binaires ELF dynamiques, le noyau est chargé de charger l'image en mémoire mais c'est le travail de `` l'interpréteur '' défini dans l'ELF en-têtes pour faire le gros du travail. Normalement, cela implique de s'assurer que toutes les bibliothèques dynamiques dépendantes sont disponibles (à l'aide de la section `` Dynamique '' qui répertorie les bibliothèques et certaines autres structures qui répertorient les symboles requis) - mais il s'agit presque d' une couche d'indirection générale.

$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses \
shared libs), stripped
$ readelf -p .interp /bin/ls
    String dump of section '.interp':
      [     0]  /lib/ld-linux.so.2

( /lib/ld-linux.so.2est également un binaire ELF, il n'a pas d'interprète et est un code binaire natif.)

Le problème avec ELF est que l'en-tête dans le binaire ( readelf -h /bin/ls) le marque pour une architecture spécifique, classe (32 ou 64 bits), endian-ness et ABI (les gros binaires "universels" d'Apple utilisent un autre format binaire Mach-O au lieu de cela, qui résout ce problème, il est originaire de NextSTEP). Cela signifie qu'un exécutable ELF doit correspondre au système sur lequel il doit être exécuté. Une trappe d'échappement est l'interpréteur, il peut s'agir de n'importe quel exécutable (y compris celui qui extrait ou mappe des sous-sections spécifiques à l'architecture du binaire d'origine et les appelle), mais vous êtes toujours limité par le ou les types d'ELF que votre système autorisera à exécuter . (FreeBSD a une manière intéressante de gérer les fichiers Linux ELF , il brandelfmodifie le champ ELF ABI.)

Il existe (en utilisant binfmt_misc) la prise en charge de Mach-O sur Linux , il y a un exemple qui vous montre comment créer et exécuter un gros binaire (32 et 64 bits). Les fourchettes de ressources / ADS , comme cela a été fait à l'origine sur le Mac, pourraient être une solution de contournement, mais aucun système de fichiers Linux natif ne prend en charge cela.

Plus ou moins la même chose s'applique aux modules du noyau, les .kofichiers sont également ELF (bien qu'ils n'aient pas d'interpréteur). Dans ce cas, il y a une couche supplémentaire qui utilise la version du noyau ( uname -r) dans le chemin de recherche, quelque chose qui pourrait théoriquement être fait à la place dans ELF avec le versioning, mais à une certaine complexité et peu de gain, je suppose.

Comme indiqué ailleurs, Linux ne prend pas en charge nativement les binaires fat, mais il existe un projet fat-binary actif: FatELF . Il existe depuis des années , il n'a jamais été intégré au noyau standard en partie à cause de problèmes de brevets (maintenant expirés). À l'heure actuelle, il nécessite à la fois la prise en charge du noyau et de la chaîne d'outils. Il n'utilise pas l' binfmt_miscapproche, cela contourne les problèmes d'en-tête ELF et permet également d'utiliser des modules de noyau lourds.

  1. Si j'ai une application compilée pour s'exécuter sur une «cible x86, linux OS version xyz», puis-je simplement exécuter le même binaire compilé sur un autre système «ARM target, linux OS version xyz»?

Pas avec ELF, ça ne vous laissera pas faire ça.

  1. Si ce n'est pas vrai, le seul moyen est d'obtenir le code source de l'application pour reconstruire / recompiler en utilisant la chaîne d'outils appropriée 'par exemple, arm-linux-gnueabi'?

La réponse simple est oui. (Les réponses compliquées incluent l'émulation, les représentations intermédiaires, les traducteurs et JIT; à l'exception du cas de "rétrogradation" d'un binaire i686 pour utiliser uniquement les opcodes i386, ils ne sont probablement pas intéressants ici, et les corrections ABI sont potentiellement aussi difficiles que la traduction de code natif. )

  1. De même, si j'ai un module de noyau chargeable (pilote de périphérique) qui fonctionne sur une «cible x86, linux OS version xyz», puis-je simplement charger / utiliser le même .ko compilé sur un autre système «cible ARM, linux OS version xyz» ?

Non, ELF ne vous laissera pas faire ça.

  1. Si ce n'est pas vrai, le seul moyen est d'obtenir le code source du pilote pour reconstruire / recompiler en utilisant la chaîne d'outils appropriée 'par exemple, arm-linux-gnueabi'?

La réponse simple est oui. Je crois que FatELF vous permet de créer un .komulti-architecture, mais à un moment donné, une version binaire pour chaque architecture prise en charge doit être créée. Les choses qui nécessitent des modules du noyau sont souvent fournies avec la source et sont construites selon les besoins, par exemple VirtualBox le fait.

C'est déjà une longue réponse décousue, il n'y a qu'un détour de plus. Le noyau a déjà une machine virtuelle intégrée, bien que dédiée: la machine virtuelle BPF qui est utilisée pour faire correspondre les paquets. Le filtre lisible par l'homme "hôte foo et non port 22") est compilé en un bytecode et le filtre de paquets du noyau l' exécute . Le nouvel eBPF n'est pas seulement pour les paquets, en théorie que le code VM est portable sur n'importe quel linux contemporain, et llvm le supporte mais pour des raisons de sécurité, il ne sera probablement pas adapté à autre chose que des règles administratives.


Maintenant, en fonction de votre générosité avec la définition d'un exécutable binaire, vous pouvez (ab) utiliser binfmt_miscpour implémenter un support binaire gras avec un script shell et des fichiers ZIP comme format de conteneur:

#!/bin/bash

name=$1
prog=${1/*\//}      # basename
prog=${prog/.woz/}  # remove extension
root=/mnt/tmpfs
root=$(TMPDIR= mktemp -d -p ${root} woz.XXXXXX)
shift               # drop argv[0], keep other args

arch=$(uname -m)                  # i686
uname_s=$(uname -s)               # Linux
glibc=$(getconf GNU_LIBC_VERSION) # glibc 2.17
glibc=${glibc// /-}               # s/ /-/g

# test that "foo.woz" can unzip, and test "foo" is executable
unzip -tqq "$1" && {
  unzip -q -o -j -d ${root} "$1"  "${arch}/${uname_s}/${glibc}/*" 
  test -x ${root}/$prog && ( 
    export LD_LIBRARY_PATH="${root}:${LD_LIBRARY_PATH}"
    #readlink -f "${root}/${prog}"   # for the curious
    exec -a "${name}" "${root}/${prog}" "$@" 
  )
  rc=$?
  #rm -rf -- "${root}/${prog}"       # for the brave
  exit $rc
}

Appelez cela "wozbin", et configurez-le avec quelque chose comme:

mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
printf ":%s:%s:%s:%s:%s:%s:%s" \
  "woz" "E" "" "woz" "" "/path/to/wozbin" ""  > /proc/sys/fs/binfmt_misc/register

Cela enregistre les .wozfichiers avec le noyau, le wozbinscript est appelé à la place avec son premier argument défini sur le chemin d'un .wozfichier appelé .

Pour obtenir un .woz fichier portable (gras) , créez simplement un test.wozfichier ZIP avec une hiérarchie de répertoires afin:

i686/ 
    \- Linux/
            \- glibc-2.12/
armv6l/
    \- Linux/
            \- glibc-2.17/

Dans chaque répertoire arch / OS / libc (un choix arbitraire), placez le testbinaire spécifique à l'architecture et les composants tels que les .sofichiers. Lorsque vous l'appelez, le sous-répertoire requis est extrait dans un système de fichiers en mémoire tmpfs ( /mnt/tmpfsici) et appelé.

Mr Spuratic
la source
0

berry boot, résolvez certains de vos problèmes .. mais cela ne résout pas le problème de fonctionnement sur arm hf, distribution distall normall / regullAr pour x86-32 / 64bit.

Je pense qu'il devrait être intégré dans isolinux (boatloader linux sur usb) un convertisseur en direct ce qui pourrait reconnaître la distribution regullar et dans ride / live convertir en hf.

Pourquoi? Parce que si chaque Linux peut être converti par Berry Boot en travaillant sur arm-hf, il pourrait être en mesure de construire un mécanisme de démarrage bery pour isolinux ce que nous démarrons en utilisant pour chacun exaple ou un disque de démarrage intégré ubuntu creat.

fdf
la source