¿Los binarios son portables en diferentes arquitecturas de CPU?

16

Mi objetivo es poder desarrollar para Linux embebido. Tengo experiencia en sistemas integrados de metal desnudo con ARM.

Tengo algunas preguntas generales sobre el desarrollo para diferentes objetivos de CPU. Mis preguntas son las siguientes:

  1. Si tengo una aplicación compilada para ejecutarse en un ' x86 target, linux OS version xyz ', ¿puedo ejecutar el mismo binario compilado en otro sistema ' ARM target, linux OS version xyz '?

  2. Si lo anterior no es cierto, la única forma es obtener el código fuente de la aplicación para reconstruir / recompilar utilizando la cadena de herramientas relevante 'por ejemplo, arm-linux-gnueabi'?

  3. Del mismo modo, si tengo un módulo de kernel cargable (controlador de dispositivo) que funciona en un ' x86 target, linux OS version xyz ', ¿puedo cargar / usar el mismo .ko compilado en otro sistema ' ARM target, linux OS version xyz '? ?

  4. Si lo anterior no es cierto, la única forma es obtener el código fuente del controlador para reconstruir / recompilar utilizando la cadena de herramientas relevante 'por ejemplo, arm-linux-gnueabi'?

foob
fuente
27
No, sí, no, sí.
hobbs
77
Es útil darse cuenta de que no tenemos un objetivo AMD y un objetivo Intel, solo un objetivo x86 para ambos. Eso es porque Intel y AMD son lo suficientemente compatibles. Entonces resulta obvio que el objetivo ARM existe por una razón específica, es decir, porque las CPU ARM no son compatibles con Intel / AMD / x86.
MSalters
1
No, a menos que sea un código de bytes diseñado para ejecutarse en un entorno de tiempo de ejecución portátil como Java Runtime. Si está escribiendo código para uso incrustado, es probable que su código dependa de optimizaciones o características específicas de procesador de bajo nivel y será muy difícil de portar, requiriendo más que solo compilación para la plataforma de destino (por ejemplo, cambios en el código de ensamblaje, posiblemente reescritura) varios módulos o todo el programa).
bwDraco
1
@MSalters: En realidad, tenemos un objetivo AMD: amd64, que a menudo se etiqueta como x86-64 (mientras que x86 suele ser un reetiquetado de i386). Afortunadamente, Intel copió (y luego amplió) la arquitectura AMD para que cualquier x86 de 64 bits pueda ejecutar binarios amd64.
slebetman

Respuestas:

42

No. Los binarios deben (re) compilarse para la arquitectura de destino, y Linux no ofrece nada como binarios gordos listos para usar . La razón es porque el código se compila en código de máquina para una arquitectura específica, y el código de máquina es muy diferente entre la mayoría de las familias de procesadores (ARM y x86, por ejemplo, son muy diferentes).

EDITAR: vale la pena señalar que algunas arquitecturas ofrecen niveles de compatibilidad con versiones anteriores (e incluso más raras, compatibilidad con otras arquitecturas); en las CPU de 64 bits, es común tener compatibilidad con versiones anteriores de las ediciones de 32 bits (pero recuerde: sus bibliotecas dependientes también deben ser de 32 bits, incluida su biblioteca estándar de C, a menos que enlace estáticamente ). También vale la pena mencionar es Itanium , donde fue posible ejecutar código x86 (solo 32 bits), aunque muy lentamente; La baja velocidad de ejecución del código x86 fue al menos parte de la razón por la que no tuvo mucho éxito en el mercado.

Tenga en cuenta que todavía no puede usar binarios compilados con instrucciones más recientes en CPU más antiguas, incluso en modos de compatibilidad (por ejemplo, no puede usar AVX en un binario de 32 bits en procesadores Nehalem x86 ; la CPU simplemente no lo admite.

Tenga en cuenta que los módulos del núcleo deben compilarse para la arquitectura relevante; Además, los módulos de kernel de 32 bits no funcionarán en kernel de 64 bits o viceversa.

Para obtener información sobre binarios de compilación cruzada (para que no tenga que tener una cadena de herramientas en el dispositivo ARM de destino), consulte la respuesta integral de grochmal a continuación.

Elizafox
fuente
1
Puede valer la pena aclarar sobre cualquier compatibilidad (o falta de ella) entre x86 y x64, dado que algunos binarios x86 pueden ejecutarse en plataformas x64. (No estoy seguro de que este sea el caso en Linux, pero en Windows, por ejemplo).
jpmc26
44
@ jpmc26 es posible en Linux; pero es posible que primero necesite instalar bibliotecas de compatibilidad. El soporte x86 es una parte no opcional de las instalaciones de Win64. En Linux es opcional; y debido a que el mundo de Linux está mucho más avanzado al hacer que las versiones de 64 bits de todo estén disponibles, algunas distribuciones no predeterminan tener (¿todas?) bibliotecas de 32 bits instaladas. (No estoy seguro de lo común que es; pero he visto algunas consultas al respecto de personas que ejecutan distribuciones mainstreamish antes.)
Dan está tocando el fuego el
@ jpmc26 Actualicé mi respuesta con sus notas; Pensé en mencionar eso, pero no quise complicar la respuesta.
Elizafox
16

Elizabeth Myers es correcta, cada arquitectura requiere un binario compilado para la arquitectura en cuestión. Para crear binarios para una arquitectura diferente a la que ejecuta su sistema, necesita a cross-compiler.


En la mayoría de los casos, necesita compilar un compilador cruzado. Solo tengo experiencia gcc(pero creo que llvm, y otros compiladores, tienen parámetros similares). Se gcclogra un compilador cruzado agregando --targeta la configuración:

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

Se necesita compilar gcc, glibcy binutilscon estos parámetros (y proporciona las cabeceras del núcleo del núcleo en el equipo de destino).

En la práctica, esto es considerablemente más complicado y aparecen diferentes errores de compilación en diferentes sistemas.

Existen varias guías sobre cómo compilar la cadena de herramientas GNU, pero recomendaré Linux From Scratch , que se mantiene continuamente y hace un muy buen trabajo al explicar lo que hacen los comandos presentados.

Otra opción es una compilación de arranque de un compilador cruzado. Gracias a la lucha de compilar compiladores cruzados para diferentes arquitecturas en diferentes arquitecturas crosstool-ngse creó. Da un arranque sobre la cadena de herramientas necesaria para construir un compilador cruzado.

crosstool-ngadmite varios tripletes de destino en diferentes arquitecturas, básicamente es un programa de arranque donde las personas dedican su tiempo a resolver los problemas que ocurren durante la compilación de una cadena de herramientas de compilación cruzada.


Varias distribuciones proporcionan compiladores cruzados como paquetes:

En otras palabras, verifique qué tiene disponible su distribución en términos de compiladores cruzados. Si su distribución no tiene un compilador cruzado para sus necesidades, siempre puede compilarlo usted mismo.

Referencias


Nota de módulos del núcleo

Si está compilando su compilador cruzado a mano, tiene todo lo que necesita para compilar los módulos del núcleo. Esto se debe a que necesita los encabezados del núcleo para compilar glibc.

Pero, si está utilizando un compilador cruzado proporcionado por su distribución, necesitará los encabezados del núcleo que se ejecuta en la máquina de destino.

grochmal
fuente
FWIW Fedora incluye también compiladores cruzados.
mattdm
@mattdm - gracias, respuesta ajustada, creo que tengo la parte correcta de la wiki de fedora vinculada.
grochmal
2
Una forma más fácil que la de Linux desde cero para que una cadena de herramientas para Linux y otra arquitectura es crosstool-ng. Es posible que desee agregar eso a la lista. Además, configurar y compilar una cadena de herramientas cruzadas GNU a mano para cualquier arquitectura dada es increíblemente complicado y mucho más tedioso que solo las --targetbanderas. Sospecho que eso es parte de por qué LLVM está ganando popularidad; Está diseñado de tal manera que no necesita una reconstrucción para apuntar a otra arquitectura; en su lugar, puede apuntar a múltiples backends usando las mismas bibliotecas frontend y optimizadora.
Iwillnotexist Idonotexist
@IwillnotexistIdonotexist: gracias, he modificado aún más la respuesta. Nunca he oído hablar de crosstool-ng antes, y parece muy útil. Tu comentario ha sido realmente muy útil para mí.
grochmal
9

Tenga en cuenta que, como último recurso (es decir, cuando no tiene el código fuente), puede ejecutar binarios en una arquitectura diferente utilizando emuladores como qemu, dosboxo exagear. Algunos emuladores están diseñados para emular sistemas que no sean Linux (por ejemplo, dosboxestá diseñado para ejecutar programas MS-DOS, y hay muchos emuladores para consolas de juegos populares). La emulación tiene una sobrecarga de rendimiento significativa: los programas emulados se ejecutan entre 2 y 10 veces más lento que sus contrapartes nativas.

Si necesita ejecutar módulos de kernel en una CPU no nativa, deberá emular todo el sistema operativo, incluido el kernel para la misma arquitectura. AFAIK es imposible ejecutar código externo dentro del kernel de Linux.

Dmitry Grigoryev
fuente
3
La penalización de velocidad para la emulación a menudo es incluso mayor que 10x, pero si uno está tratando de ejecutar código escrito para una máquina de 16Mhz en una máquina de 4GHz (una diferencia de velocidad de 250: 1), un emulador que tiene una penalización de velocidad de 50: 1 aún puede ejecutar código mucho más rápido de lo que se hubiera ejecutado en la plataforma original.
supercat
7

No solo los binarios no son portátiles entre x86 y ARM, sino que también hay diferentes tipos de ARM .

El que probablemente encuentre en la práctica es ARMv6 vs ARMv7. Raspberry Pi 1 es ARMv6, las versiones posteriores son ARMv7. Por lo tanto, es posible compilar código en los posteriores que no funciona en Pi 1.

Afortunadamente, uno de los beneficios del software libre y de código abierto es tener el código fuente para que pueda reconstruirlo en cualquier arquitectura. Aunque esto puede requerir algo de trabajo.

(El control de versiones ARM es confuso, pero si hay una V antes del número, está hablando de la arquitectura del conjunto de instrucciones (ISA). Si no existe, es un número de modelo como "Cortex M0" o "ARM926EJS". Los números de modelo no tienen nada que ver. hacer con números ISA.)

pjc50
fuente
2
... y luego hay incluso diferentes sub-sabores para el mismo sabor ARM, e incluso diferentes ABI para el mismo hardware exacto (estoy pensando en todo el desorden de punto flotante ARM soft / softfp / hard).
Matteo Italia
1
@MatteoItalia Ugh. Los múltiples ABI eran un error, una cura para algo que era peor que la enfermedad. Algunos ARM no tenían registros VFP o NEON en absoluto, algunos tenían 16, otros 32. En Cortex-A8 y versiones anteriores, el motor NEON ejecutaba una docena de CC detrás del resto del núcleo, por lo que transferir una salida vectorial a un GPR cuesta un lote. ARM ha llegado a hacer lo correcto: exigir un gran subconjunto común de características.
Iwillnotexist Idonotexist
7

Siempre necesitas apuntar a una plataforma. En el caso más simple, la CPU de destino ejecuta directamente el código compilado en el binario (esto corresponde aproximadamente a los ejecutables COM de MS DOS). Consideremos dos plataformas diferentes que acabo de inventar: Armistice e Intellio. En ambos casos, tendremos un programa simple hello world que genera 42 en la pantalla. También supondré que está utilizando un lenguaje multiplataforma de manera independiente de la plataforma, por lo que el código fuente es el mismo para ambos:

Print(42)

En Armistice, tiene un controlador de dispositivo simple que se encarga de imprimir números, por lo que todo lo que tiene que hacer es enviarlo a un puerto. En nuestro lenguaje ensamblador portátil, esto correspondería a algo como esto:

out 1234h, 42

Sin embargo, o el sistema Intellio no tiene tal cosa, por lo que tiene que pasar por otras capas:

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

¡Vaya, ya tenemos una diferencia significativa entre los dos, incluso antes de llegar al código de máquina! Esto correspondería aproximadamente al tipo de diferencia que tiene entre Linux y MS DOS, o una PC IBM y un X-Box (aunque ambos pueden usar la misma CPU).

Pero para eso están los sistemas operativos. Supongamos que tenemos un HAL que se asegura de que todas las configuraciones de hardware diferentes se manejen de la misma manera en la capa de aplicación; básicamente, usaremos el enfoque Intellio incluso en Armistice, y nuestro código de "ensamblaje portátil" termina igual. Esto lo usan tanto los sistemas modernos tipo Unix como Windows, a menudo incluso en escenarios integrados. Bien, ahora podemos tener el mismo código de ensamblaje verdaderamente portátil tanto en Armistice como en Intellio. ¿Pero qué hay de los binarios?

Como hemos supuesto, la CPU necesita ejecutar el binario directamente. Veamos la primera línea de nuestro código mov a, 10h, en Intellio:

20 10

Oh. Resulta que mov a, constantes tan popular que tiene sus propias instrucciones, con su propio código de operación. ¿Cómo maneja Armistice esto?

36 01 00 10

Hmm Existe el código de operación para mov.reg.imm, por lo que necesitamos otro argumento para seleccionar el registro al que estamos asignando. Y la constante es siempre una palabra de 2 bytes, en notación big-endian: así es como se diseñó Armistice, de hecho, todas las instrucciones en Armistice tienen 4 bytes de longitud, sin excepciones.

Ahora imagine ejecutar el binario desde Intellio en Armistice: la CPU comienza a decodificar la instrucción, encuentra el código de operación 20h. En Armisticio, esto corresponde, por ejemplo, a la and.imm.reginstrucción. Intenta leer la palabra constante de 2 bytes (que lee 10XX, ya es un problema), y luego el número de registro (otro XX). Estamos ejecutando la instrucción incorrecta, con los argumentos incorrectos. Y lo que es peor, la próxima instrucción será completamente falsa, porque en realidad comimos otra instrucción, pensando que eran datos.

La aplicación no tiene posibilidades de funcionar, y lo más probable es que se bloquee o cuelgue casi de inmediato.

Ahora, esto no significa que un ejecutable siempre necesite decir que se ejecuta en Intellio o Armistice. Solo necesita definir una plataforma que sea independiente de la CPU (como bashen Unix), o tanto la CPU como el sistema operativo (como Java o .NET, y hoy en día incluso JavaScript, más o menos). En este caso, la aplicación puede usar un ejecutable para todas las CPU y sistemas operativos diferentes, mientras que hay alguna aplicación o servicio en el sistema de destino (que apunta directamente a la CPU y / o sistema operativo correcto) que traduce el código independiente de la plataforma en algo que La CPU realmente puede ejecutarse. Esto puede o no tener un impacto en el rendimiento, el costo o la capacidad.

Las CPU generalmente vienen en familias. Por ejemplo, todas las CPU de la familia x86 tienen un conjunto común de instrucciones que están codificadas exactamente de la misma manera, por lo que cada CPU x86 puede ejecutar todos los programas x86, siempre que no intente usar ninguna extensión (por ejemplo, operaciones de punto flotante u operaciones vectoriales). En x86, los ejemplos más comunes hoy en día son Intel y AMD, por supuesto. Atmel es una compañía bien conocida que diseña CPU en la familia ARM, bastante popular para dispositivos integrados. Apple también tiene CPU ARM propias, por ejemplo.

Pero ARM es totalmente incompatible con x86: tienen requisitos de diseño muy diferentes y tienen muy poco en común. Las instrucciones tienen códigos de operación completamente diferentes, se decodifican de manera diferente, las direcciones de memoria se tratan de manera diferente ... Es posible hacer un binario que se ejecute tanto en una CPU x86 como en una CPU ARM, utilizando algunas operaciones seguras para distingue entre los dos y salta a dos conjuntos de instrucciones completamente diferentes, pero aún así significa que tiene instrucciones separadas para ambas versiones, con solo un bootstrapper que elige el conjunto correcto en tiempo de ejecución.

Luaan
fuente
3

Es posible volver a plantear esta pregunta en un entorno que podría ser más familiar. Por analogia:

"Tengo un programa Ruby que quiero ejecutar, pero mi plataforma solo tiene un intérprete de Python. ¿Puedo usar el intérprete de Python para ejecutar mi programa Ruby o tengo que reescribir mi programa en Python?"

Una arquitectura de conjunto de instrucciones ("destino") es un lenguaje, un "lenguaje de máquina", y diferentes CPU implementan diferentes idiomas. Entonces, pedirle a una CPU ARM que ejecute un binario Intel es muy parecido a intentar ejecutar un programa Ruby usando un intérprete de Python.

Jander
fuente
2

gcc usa los términos '' arquitectura '' para referirse al '' conjunto de instrucciones '' de una CPU específica, y "objetivo" cubre la combinación de CPU y arquitectura, junto con otras variables como ABI, libc, endian-ness y más (posiblemente incluyendo "metal desnudo"). Un compilador típico tiene un conjunto limitado de combinaciones de destino (probablemente una ABI, una familia de CPU, pero posiblemente ambas de 32 y 64 bits). Un compilador cruzado generalmente significa un compilador con un objetivo distinto del sistema en el que se ejecuta, o uno con múltiples objetivos o ABI (ver también esto ).

¿Los binarios son portables en diferentes arquitecturas de CPU?

En general, no. Un binario en términos convencionales es el código de objeto nativo para una CPU o familia de CPU en particular. Pero, hay varios casos en los que pueden ser moderadamente a altamente portátiles:

  • una arquitectura es un superconjunto de otra (comúnmente los binarios x86 se dirigen a i386 o i686 en lugar del último y mejor x86, por ejemplo -march=core2)
  • una arquitectura proporciona emulación nativa o traducción de otra (es posible que haya oído hablar de Crusoe ) o proporciona coprocesadores compatibles (por ejemplo, PS2 )
  • el sistema operativo y el tiempo de ejecución admiten multiarch (por ejemplo, la capacidad de ejecutar binarios x86 de 32 bits en x86_64), o hacer que el VM / JIT sea perfecto (Android usando Dalvik o ART )
  • hay soporte para binarios "gordos" que esencialmente contienen código duplicado para cada arquitectura compatible

Si de alguna manera logras resolver este problema, el otro problema binario portátil de innumerables versiones de biblioteca (glibc te estoy mirando) se presentará. (La mayoría de los sistemas integrados lo salvan de ese problema en particular al menos).

Si aún no lo ha hecho, ahora es un buen momento para correr gcc -dumpspecsy gcc --target-helpver a qué se enfrenta.

Los binarios gordos tienen varios inconvenientes , pero aún tienen usos potenciales ( EFI ).

Sin embargo, faltan otras dos consideraciones en las otras respuestas: ELF y el intérprete ELF, y el soporte del kernel de Linux para formatos binarios arbitrarios . No entraré en detalles sobre los binarios o el código de bytes para procesadores no reales aquí, aunque es posible tratarlos como "nativos" y ejecutar Java o binarios compilados de código de bytes de Python , tales binarios son independientes de la arquitectura de hardware (pero dependen en la versión de VM relevante, que finalmente ejecuta un binario nativo).

Cualquier sistema Linux contemporáneo utilizará archivos binarios ELF (detalles técnicos en este PDF ), en el caso de los archivos binarios ELF dinámicos, el núcleo se encarga de cargar la imagen en la memoria, pero es el trabajo del "intérprete" establecido en el ELF encabezados para hacer el trabajo pesado. Normalmente esto implica asegurarse de que todas las bibliotecas dinámicas dependientes estén disponibles (con la ayuda de la sección '' Dinámica '' que enumera las bibliotecas y algunas otras estructuras que enumeran los símbolos requeridos), pero esta es casi una capa de indirección de propósito general.

$ 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.2también es un binario ELF, no tiene un intérprete y es un código binario nativo).

El problema con ELF es que el encabezado en el binario ( readelf -h /bin/ls) lo marca para una arquitectura específica, clase (32 o 64 bits), endian-ness y ABI (los binarios gordos "universales" de Apple usan un formato binario alternativo Mach-O en cambio, lo que resuelve este problema, esto se originó en NextSTEP). Esto significa que un ejecutable ELF debe coincidir con el sistema en el que se ejecutará. Un intérprete de escape es el intérprete, este puede ser cualquier ejecutable (incluido uno que extrae o asigna subsecciones específicas de la arquitectura del binario original y las invoca), pero aún está limitado por el tipo (s) de ELF que su sistema permitirá ejecutar . (FreeBSD tiene una forma interesante de manejar archivos ELF de Linux , brandelfmodifica el campo ELF ABI).

Hay (uso binfmt_misc) de soporte para Mach-O en Linux , hay un ejemplo que muestra cómo crear y ejecutar un binario gordo (32 y 64 bits). Las bifurcaciones de recursos / ADS , como se hizo originalmente en Mac, podrían ser una solución, pero ningún sistema de archivos Linux nativo lo admite.

Más o menos lo mismo se aplica a los módulos del núcleo, los .koarchivos también son ELF (aunque no tienen un conjunto de intérpretes). En este caso, hay una capa adicional que usa la versión del kernel ( uname -r) en la ruta de búsqueda, algo que teóricamente podría hacerse en su lugar en ELF con versiones, pero sospecho que con cierta complejidad y poca ganancia.

Como se señaló en otra parte, Linux no admite de forma nativa binarios gordos, pero hay un proyecto activo binario gordo: FatELF . Ha existido durante años , nunca se integró en el núcleo estándar en parte debido a preocupaciones de patentes (ahora expiradas). En este momento requiere soporte de kernel y toolchain. No utiliza el binfmt_miscenfoque, esto evita los problemas de encabezado ELF y también permite módulos de kernel gordos.

  1. Si tengo una aplicación compilada para ejecutarse en un 'x86 target, linux OS version xyz', ¿puedo ejecutar el mismo binario compilado en otro sistema 'ARM target, linux OS version xyz'?

No con ELF, no te permitirá hacer esto.

  1. Si lo anterior no es cierto, la única forma es obtener el código fuente de la aplicación para reconstruir / recompilar utilizando la cadena de herramientas relevante 'por ejemplo, arm-linux-gnueabi'?

La respuesta simple es sí. (Las respuestas complicadas incluyen emulación, representaciones intermedias, traductores y JIT; a excepción del caso de "degradar" un binario i686 para usar solo códigos de operación i386, probablemente no sean interesantes aquí, y las reparaciones ABI son potencialmente tan difíciles como traducir código nativo. )

  1. Del mismo modo, si tengo un módulo de kernel cargable (controlador de dispositivo) que funciona en un 'x86 target, linux OS versión xyz', ¿puedo cargar / usar el mismo .ko compilado en otro sistema 'ARM target, linux OS version xyz'? ?

No, ELF no te dejará hacer esto.

  1. Si lo anterior no es cierto, la única forma es obtener el código fuente del controlador para reconstruir / recompilar utilizando la cadena de herramientas relevante 'por ejemplo, arm-linux-gnueabi'?

La respuesta simple es sí. Creo que FatELF le permite construir una .koarquitectura múltiple, pero en algún momento se debe crear una versión binaria para cada arquitectura compatible. Las cosas que requieren módulos del núcleo a menudo vienen con la fuente y se compilan según sea necesario, por ejemplo, VirtualBox hace esto.

Esta ya es una respuesta larga, solo hay un desvío más. El núcleo ya tiene una máquina virtual integrada, aunque dedicada: la máquina virtual BPF que se usa para unir paquetes. El filtro legible por humanos "host foo and not port 22") se compila en un código de bytes y el filtro de paquetes del núcleo lo ejecuta . El nuevo eBPF no es solo para paquetes, en teoría que el código VM es portátil en cualquier linux contemporáneo, y llvm lo admite, sino que por razones de seguridad probablemente no sea adecuado para nada más que reglas administrativas.


Ahora, dependiendo de cuán generoso sea con la definición de un ejecutable binario, puede (ab) usarlo binfmt_miscpara implementar soporte binario gordo con un script de shell y archivos ZIP como formato contenedor:

#!/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
}

Llame a esto "wozbin" y configúrelo con algo como:

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

Esto registra .wozarchivos con el kernel, el wozbinscript se invoca en su lugar con su primer argumento establecido en la ruta de un .wozarchivo invocado .

Para obtener un .woz archivo portátil (gordo) , simplemente cree un test.wozarchivo ZIP con una jerarquía de directorios para:

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

Dentro de cada directorio arch / OS / libc (una opción arbitraria) coloque el testbinario específico de la arquitectura y los componentes, como los .soarchivos. Cuando lo invoca, el subdirectorio requerido se extrae en un sistema de archivos en memoria tmpfs ( /mnt/tmpfsaquí) y se invoca.

Sr. púrpura
fuente
0

Berry boot, resuelve algunos de tus problemas ... pero no resuelve el problema de cómo ejecutar en arm hf, normall / regullAr linux distro para x86-32 / 64bit.

Creo que debería estar integrado en isolinux (boatloader linux en usb) algún convertidor en vivo que pueda reconocer la distribución regular y en paseo / conversión en vivo a hf.

¿Por qué? Porque si cada linux se puede convertir mediante arranque de baya para trabajar en arm-hf, entonces podría ser capaz de construir un mecanismo de arranque bery en isolinux, lo que arrancamos usando eacher exaple o un disco de arranque de ubuntu creado.

fdf
fuente