Jak stwierdzić, czy system Linux jest dużym endianem czy małym endianem?

91

Wiem, że niektóre procesory to Big Endian, a inne to Little Endian. Ale czy istnieje polecenie, skrypt bash, skrypt Pythona lub seria poleceń, których można użyć w wierszu poleceń, aby ustalić, czy system to Big Endian czy Little Endian? Coś jak:

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

Czy może łatwiej jest po prostu określić, jakiego procesora używa system i przejść do tego, aby określić jego Endianess?

Jake Wilson
źródło
Oto rozwiązanie wykorzystujące perl: stackoverflow.com/questions/2610849/…
slu

Odpowiedzi:

110

W systemie Big Endian (Solaris na SPARC)

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

0

Na małym systemie endian (Linux na x86)

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

1


Powyższe rozwiązanie jest sprytne i działa świetnie w systemach Linux * 86 i Solaris Sparc.

Potrzebowałem rozwiązania opartego tylko na powłoce (bez Perla), które działałoby również w systemach AIX / Power i HPUX / Itanium. Niestety dwa ostatnie nie są dobre: ​​AIX zgłasza „6”, a HPUX podaje pustą linię.

Korzystając z twojego rozwiązania, udało mi się stworzyć coś, co działałoby na tych wszystkich systemach uniksowych:

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

Jeśli chodzi o rozwiązanie w języku Python, które ktoś opublikował, nie działa w Jython, ponieważ JVM traktuje wszystko jako duże. Jeśli ktokolwiek może zmusić go do działania w Jython, proszę pisać!

Znalazłem też to, co tłumaczy endianizm różnych platform. Niektóre urządzenia mogą działać w dowolnym trybie, w zależności od wybranych przez O / S: http://labs.hoffmanlabs.com/node/544


Jeśli zamierzasz użyć awk, tę linię można uprościć do:

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

W przypadku małych urządzeń z systemem Linux, które nie mają „od” (powiedzmy OpenWrt), spróbuj „hexdump”:

echo -n I | hexdump -o | awk '{ print substr($2,6,1); exit}'
krissi
źródło
2
Nawiasem mówiąc, jest to wielka litera I(oko), a nie mała litera l(ell).
Dennis Williamson,
1
(Solaris) -> (Solaris, Sparc), chociaż Sparc> = V9 to wersja bi endian.
Cristian Ciupitu,
1
Chcesz wyjaśnić, jak to działa?
Massimo,
Nie działa to na Androidzie (Nexus 5). Nie jestem pewien, dlaczego ...
wjandrea,
printf "\x1" | od -to2 | awk 'NR==1{print$2==1}'
Kaz
35

Jeśli jesteś w dość niedawnym maszynie Linux (najczęściej coś po roku 2012) , a następnie lscputeraz zawiera następujące informacje:

$ lscpu | grep Endian
Byte Order:            Little Endian

Zostało to dodane do lscpuwersji 2.19, która znajduje się w Fedorze> = 17, CentOS> = 6.0, Ubuntu> = 12.04.

Zauważ, że znalazłem tę odpowiedź z tej niesamowitej odpowiedzi na Unix.SE . Ta odpowiedź zawiera wiele istotnych informacji, ten post jest tylko jej streszczeniem.

dotancohen
źródło
31

Oto bardziej elegancki, jednowierszowy skrypt Pythona

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

kod wyjścia 0oznacza duży endian i 1oznacza mały endian

lub po prostu zmień sys.exitna, printaby uzyskać wydruk

mchurichi
źródło
4
To nie zadziała w systemach RHEL 5.x / CentOS 5.x, które działają w języku Python 2.4.x. Oto poprawka:python -c "import sys;sys.exit(int(sys.byteorder!='big'))"
JPaget
10

Główną odpowiedź można nieco uprościć, używając awk:

W systemie Big Endian (Solaris, SPARC)

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

W systemie Little Endian (Linux, Intel)

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

Nowsze jądra Linux

Od wersji 2.19 pakietu util-linux polecenie lscpuzaczęło się, włączając pole związane z Endianness. Teraz możesz po prostu użyć tego polecenia, aby się tego dowiedzieć:

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

Zostało to potwierdzone w Ubuntu 12.10 i CentOS 6. Dlatego zechciałbym założyć, że większość jąder Linuksa 3.0+ oferuje to teraz.

W systemach Debian / Ubuntu możesz także użyć tego polecenia, nie wiedząc, kiedy będzie dostępne:

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

Bibliografia

slm
źródło
9

Ten skrypt w Pythonie powinien działać dla Ciebie:

#!/usr/bin/env python
from struct import pack
if pack('@h', 1) == pack('<h', 1):
    print "Little Endian"
else:
    print "Big Endian"
Dennis Williamson
źródło
4
Jedna wkładka: python -c "from struct import pack;import sys;sys.exit(int(pack('@h',1)==pack('<h',1)))". Kod wyjścia to 0 dla big endian i 1 dla little endian.
Cristian Ciupitu,
7
python -c "import sys; print(sys.byteorder)"

Wypisuje endianessę systemu.

prembhaskal
źródło
6

Możesz skorzystać z formatu pliku ELF, aby określić endianizm swojego systemu. Na przykład wydrukuj pierwsze sześć bajtów dowolnego pliku ELF w postaci szesnastkowej:

xxd -c 1 -l 6 /bin/ls

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

Jeśli ostatni wiersz (szósty bajt) to 01, zgodnie z formatem ELF , 01 to mały endian, a 02 to duży endian.

Jeśli nie masz xxdna swoim urządzeniu (i masz zajęty), spróbuj tego:

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

Tong Zhou
źródło
Myślę, że masz na myśli dowolny ELF ... Ponieważ istnieją inne typy plików wykonywalnych, w tym skrypty powłoki, perl, python itp. Jednak nie mówię, że się mylisz - po prostu mówisz, że warto pamiętać, że istnieją inne typy plików wykonywalnych (i dla zainteresowania kod znajduje się w segmencie tekstowym, stąd błąd zajętości starego pliku tekstowego).
Pryftan
1
@Pryftan Dzięki za zwrócenie na to uwagi. Naprawiłem to!
Tong Zhou,
@TongZhou Welcome; miło mi pomóc!
Pryftan
Niesamowite! Pierwsza metoda działania dla wbudowanych systemów operacyjnych opartych na busyboksie.
ogurets
3

Znalazłem sposób na zrobienie tego w Jython. Ponieważ Jython (Python na JVM) działa na maszynie wirtualnej, zawsze zgłasza duży endian, niezależnie od sprzętu.

To rozwiązanie działa w systemach Linux, Solaris, AIX i HPUX. Nie testowałem w systemie Windows:

    from java.lang import System
    for property, value in dict(System.getProperties()).items():
        if property.endswith('cpu.endian'):
            return value
bla
źródło
2

Polecenie jednowierszowe oparte na formacie ELF:
hexdump -s 5 -n 1 /bin/sh

fae
źródło
Edycja: -n 1, przepraszam;)
fae
1
Jest to dokładnie ta sama metoda, co poprzednia odpowiedź , która również zawiera więcej szczegółów niż Twoja.
kasperd
0

Nieco inne wymaganie: Potrzebuję takiego testu w skrypcie konfiguracyjnym kompilacji programu, aby ustalić, czy docelowa maszyna do kompilacji jest bitowa czy mała, bez wykonywania kodu . Skrypt musi zostać złożony #define HAVE_LITTLE_ENDIAN 1w config.hnagłówku, w przeciwnym razie #define HAVE_LITTLE_ENDIAN 0.

Komputer docelowy kompilacji może różnić się od maszyny kompilacji, ponieważ możemy kompilować się wzajemnie, co również wyjaśnia, dlaczego test nie może próbować uruchomić żadnego skompilowanego kodu. Nie ma mowy o małym programie C z printfinstrukcją, która wyrzuca odpowiedź.

Możliwym rozwiązaniem jest to. Generujemy plik o nazwie, conftest.cktóry zawiera:

#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                                                                          
};

Teraz kompilujemy to conftest.oza pomocą:

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

Następnie uruchamiamy:

$ strings conftest.o
PSILXINUEROCMIWD

Jeśli ciąg PSILXINUEROCMIWDwystąpi, celem jest little-endian. Jeśli ciąg LISPUNIXCOREDWIMwystąpi, jest to big-endian. Jeśli nie wystąpi żaden ciąg znaków lub, co bardziej zaskakujące, oba wystąpią, oznacza to, że test się nie powiódł.

Takie podejście działa, ponieważ obliczone w programie stałe „fourcc” mają wartości niezależne od maszyny, oznaczające te same liczby całkowite niezależnie od endianowości. Ich reprezentacja pamięci w pliku obiektowym jest zgodna z endianizmem systemu docelowego i jest to widoczne w widoku opartym na znakach pod strings.

Dwa zerowe słowa zabezpieczające zapewniają, że ciąg jest izolowany. Nie jest to absolutnie konieczne, ale zapewnia, że ​​szukany ciąg nie jest osadzony w innym ciągu, co oznacza, że stringswyprowadzi go sam w wierszu.

PS USPELLmakro nie nawiasy wstawia argumentów, ponieważ jest spreparowane do tego konkretnego celu, a nie do ponownego użycia.

Kaz
źródło
Nie jest to konieczne dla wszystkich projektów, ale czy autoconf / automake nie ma tej kontroli? Moje projekty są zawsze na tyle małe, że mogę tworzyć własne pliki Makefile (choć nie zawsze podstawowe), więc tak naprawdę nie znam tych narzędzi poza wprowadzaniem modyfikacji w razie potrzeby i ogólnego interfejsu .. ale zastanawiam się, czy są one wykrywalne. Być może nie potrzebujesz go, nawet jeśli tak jest, po prostu pomyślałem, że wyrzucę tę możliwość.
Pryftan