Come capire se un sistema Linux è big endian o little endian?


91

So che alcuni processori sono Big Endian e altri sono Little Endian. Ma esiste un comando, uno script bash, uno script python o una serie di comandi che possono essere utilizzati dalla riga di comando per determinare se un sistema è Big Endian o Little Endian? Qualcosa di simile a:

if <some code> then
    echo Big Endian
else
    echo Little Endian
fi

O è più semplice determinare quale processore sta usando il sistema e procedere con quello per determinare la sua Endianess?


Ecco la soluzione utilizzando Perl: stackoverflow.com/questions/2610849/...
SLU

Risposte:


110

Su un sistema Big Endian (Solaris su SPARC)

$ echo -n I | od -to2 | head -n1 | cut -f2 -d" " | cut -c6 

0

Su un piccolo sistema endian (Linux su x86)

$ echo -n I | od -to2 | head -n1 | cut -f2 -d" " | cut -c6 

1


La soluzione sopra è intelligente e funziona alla grande per Linux * 86 e Solaris Sparc.

Avevo bisogno di una soluzione solo shell (no Perl) che funzionasse anche su AIX / Power e HPUX / Itanium. Purtroppo gli ultimi due non giocano bene: AIX riporta "6" e HPUX dà una linea vuota.

Usando la tua soluzione, sono stato in grado di creare qualcosa che ha funzionato su tutti questi sistemi Unix:

$ echo I | tr -d [:space:] | od -to2 | head -n1 | awk '{print $2}' | cut -c6

Per quanto riguarda la soluzione Python pubblicata da qualcuno, non funziona in Jython perché la JVM considera tutto quanto più grande. Se qualcuno riesce a farlo funzionare in Jython, si prega di pubblicare!

Inoltre, ho trovato questo, che spiega l'endianità di varie piattaforme. Alcuni hardware possono funzionare in entrambe le modalità a seconda di ciò che l'O / S seleziona: http://labs.hoffmanlabs.com/node/544


Se hai intenzione di usare awk questa linea può essere semplificata per:

echo -n I | od -to2 | awk '{ print substr($2,6,1); exit}'

Per i piccoli box Linux che non hanno "od" (diciamo OpenWrt), prova "hexdump":

echo -n I | hexdump -o | awk '{ print substr($2,6,1); exit}'

2
A proposito, quello è un maiuscolo I(occhio) piuttosto che un minuscolo l(ell).
Dennis Williamson,

1
(Solaris) -> (Solaris, Sparc), sebbene Sparc> = V9 sia bi-endico.
Cristian Ciupitu,

1
Ti interessa spiegare come funziona?
Massimo

Questo non sembra funzionare su Android (Nexus 5). Non so perché ...
wjandrea,

printf "\x1" | od -to2 | awk 'NR==1{print$2==1}'
Kaz,

35

Se siete su una abbastanza recente macchina Linux (qualsiasi cosa dopo il 2012) , allora lscpuora contiene le seguenti informazioni:

$ lscpu | grep Endian
Byte Order:            Little Endian

Questo è stato aggiunto alla lscpuversione 2.19, che si trova in Fedora> = 17, CentOS> = 6.0, Ubuntu> = 12.04.

Si noti che ho trovato questa risposta da questa risposta formidabile su Unix.SE . Quella risposta contiene molte informazioni pertinenti, questo post ne è solo un riassunto.


31

Ecco uno script di una riga in pitone più elegante

python -c "import sys;sys.exit(0 if sys.byteorder=='big' else 1)"

il codice di uscita 0significa big endian e 1significa little endian

o passare sys.exita printper un output stampabile


4
Questo non funzionerà sui sistemi RHEL 5.x / CentOS 5.x che eseguono Python 2.4.x. Ecco una soluzione:python -c "import sys;sys.exit(int(sys.byteorder!='big'))"
JPaget

10

La risposta principale può essere leggermente semplificata usando awk:

Su un sistema Big Endian (Solaris, SPARC)

$ echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}'
0

Su un sistema Little Endian (Linux, Intel)

$ echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}'
1

Kernel Linux più recenti

A partire dalla versione 2.19 del pacchetto util-linux il comando è lscpuiniziato includendo un campo relativo a Endianness. Quindi ora puoi semplicemente usare questo comando per scoprirlo:

$ lscpu | grep -i byte
Byte Order:            Little Endian

Ciò è stato confermato su Ubuntu 12.10 e CentOS 6. Quindi sarei disposto a supporre che la maggior parte dei kernel Linux 3.0+ ora offra questo.

Sui sistemi Debian / Ubuntu puoi anche usare questo comando, non sicuro di quando è diventato disponibile:

$ dpkg-architecture | grep -i end
DEB_BUILD_ARCH_ENDIAN=little
DEB_HOST_ARCH_ENDIAN=little

Riferimenti


9

Questo script Python dovrebbe funzionare per te:

#!/usr/bin/env python
from struct import pack
if pack('@h', 1) == pack('<h', 1):
    print "Little Endian"
else:
    print "Big Endian"

4
Uno di linea: python -c "from struct import pack;import sys;sys.exit(int(pack('@h',1)==pack('<h',1)))". Il codice di uscita è 0 per big endian e 1 per little endian.
Cristian Ciupitu,

7
python -c "import sys; print(sys.byteorder)"

Stamperebbe l'endianità del sistema.


6

Puoi sfruttare il formato di file ELF per determinare l'endianness del tuo sistema. Ad esempio, stampare i primi sei byte di un file ELF arbitrario in esadecimale:

xxd -c 1 -l 6 /bin/ls

0000000: 7f . 0000001: 45 E 0000002: 4c L 0000003: 46 F 0000004: 02 . 0000005: 01 .

Se l'ultima riga (il byte sixed) è 01, secondo il formato ELF , 01 è little endian e 02 è big endian.

Se non ne hai uno xxdsulla tua scatola (e hai busybox), prova questo:

hexdump -s 5 -n 1 -C /bin/busybox


Penso che tu intenda un ELF arbitrario ... Dal momento che ci sono altri tipi eseguibili tra cui script di shell, perl, python, ecc. Non dire che ti sbagli altrimenti però - solo dicendo che vale la pena ricordare che ci sono altri tipi eseguibili (e per interesse il codice è nel segmento di testo, quindi il vecchio errore di occupato file di testo).
Pryftan,

1
@Pryftan Grazie per averlo sottolineato. Corretto!
Tong Zhou,

@TongZhou Welcome; felice di essere di aiuto!
Pryftan,

Eccezionale! Primo metodo per funzionare con sistemi operativi embedded basati su busybox.
Ogurets,

3

Ho trovato un modo per farlo in Jython. Poiché Jython (Python su JVM) viene eseguito su una macchina virtuale, riporta sempre big endian, indipendentemente dall'hardware.

Questa soluzione funziona per Linux, Solaris, AIX e HPUX. Non ho testato su Windows:

    from java.lang import System
    for property, value in dict(System.getProperties()).items():
        if property.endswith('cpu.endian'):
            return value

2

Un comando a riga singola basato sul formato ELF:
hexdump -s 5 -n 1 /bin/sh


Modifica: -n 1, scusa;)
fae

1
Questo è esattamente lo stesso metodo di una risposta precedente , che ha anche fornito più dettagli del tuo.
Kasperd,

0

Requisito leggermente diverso: ho bisogno di un test come questo in uno script di configurazione della compilazione del programma per determinare se la macchina di destinazione della compilazione è bit o little endian, senza eseguire il codice . Lo script deve depositare #define HAVE_LITTLE_ENDIAN 1in config.hun'intestazione, altrimenti #define HAVE_LITTLE_ENDIAN 0.

La macchina di destinazione della compilazione potrebbe essere diversa dalla macchina di compilazione, poiché potremmo eseguire la compilazione incrociata, il che spiega anche perché il test non deve tentare di eseguire alcun codice compilato. È fuori discussione avere un piccolo programma C con una printfdichiarazione che sputa la risposta.

Una possibile soluzione è questa. Generiamo un file chiamato conftest.cche contiene questo:

#define USPELL(C0, C1, C2, C3) \                                             
  ((unsigned) C0 << 24 | \                                              
   (unsigned) C1 << 16 | \                                              
   (unsigned) C2 << 8 | (unsigned) C3)                                       

unsigned x[6] = {                                                       
  0,                                                                         
  USPELL('L', 'I', 'S', 'P'),                                                
  USPELL('U', 'N', 'I', 'X'),                                                
  USPELL('C', 'O', 'R', 'E'),                                                
  USPELL('D', 'W', 'I', 'M'),                                                
  0                                                                          
};

Ora, lo compiliamo conftest.ousando:

$ /path/to/cross-compiling/cc conftest.c -c

Quindi corriamo:

$ strings conftest.o
PSILXINUEROCMIWD

Se si PSILXINUEROCMIWDverifica la stringa , la destinazione è little-endian. Se la stringa si LISPUNIXCOREDWIMverifica, è big-endian. Se non si verifica nessuna stringa o, ancor più sorprendentemente, entrambe le funzioni, il test ha avuto esito negativo.

Questo approccio funziona perché le costanti "fourcc" calcolate nel programma hanno valori indipendenti dalla macchina, che indicano gli stessi numeri interi indipendentemente dall'endianness. La loro rappresentazione di archiviazione nel file oggetto segue l'endianità del sistema di destinazione, ed è visibile tramite la vista basata sui caratteri in strings.

Le due parole zero guard assicurano che la stringa sia isolata. Ciò non è strettamente necessario, ma garantisce che la stringa che stiamo cercando non sia incorporata in qualche altra stringa, il che significa che la stringsgenererà su una riga da sola.

PS la USPELLmacro non è tra parentesi negli inserimenti degli argomenti perché è predisposta per questo scopo specifico, non per il riutilizzo.


Non è necessario per tutti i progetti, ma autoconf / automake non ha questo controllo? I miei progetti sono sempre abbastanza piccoli in cui posso creare i miei Makefile (anche se non sempre di base), quindi non conosco davvero quegli strumenti oltre a apportare alcune modifiche quando necessario e l'interfaccia generale ... ma mi chiedo se hanno un rilevamento. Forse non ne avevi bisogno anche se lo fosse, pensavo solo che avrei buttato fuori la possibilità.
Pryftan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.