Como saber se um sistema Linux é big endian ou little endian?

91

Eu sei que certos processadores são Big Endian e outros são Little Endian. Mas existe um comando, script bash, script python ou série de comandos que podem ser usados ​​na linha de comando para determinar se um sistema é Big Endian ou Little Endian? Algo como:

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

Ou é mais simples determinar apenas qual processador o sistema está usando e acompanhá-lo para determinar sua Endianess?

Jake Wilson
fonte
Aqui está a solução usando o perl: stackoverflow.com/questions/2610849/…
slu 15/10/10

Respostas:

110

Em um sistema Big Endian (Solaris em SPARC)

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

0 0

Em um pequeno sistema endian (Linux on x86)

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

1


A solução acima é inteligente e funciona muito bem para Linux * 86 e Solaris Sparc.

Eu precisava de uma solução somente de shell (sem Perl) que também funcionasse no AIX / Power e HPUX / Itanium. Infelizmente, os dois últimos não são bons: o AIX reporta "6" e o HPUX fornece uma linha vazia.

Usando sua solução, pude criar algo que funcionasse em todos esses sistemas Unix:

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

Em relação à solução Python que alguém postou, ela não funciona no Jython porque a JVM trata tudo como Big. Se alguém puder fazê-lo funcionar em Jython, por favor poste!

Além disso, eu achei isso, o que explica o endianness de várias plataformas. Alguns hardwares podem operar nos dois modos, dependendo do que o sistema operacional seleciona: http://labs.hoffmanlabs.com/node/544


Se você usar o awk, esta linha poderá ser simplificada para:

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

Para pequenas caixas Linux que não possuem 'od' (por exemplo, OpenWrt), tente 'hexdump':

echo -n I | hexdump -o | awk '{ print substr($2,6,1); exit}'
krissi
fonte
2
Essa é uma maiúscula I(olho) ao invés de minúscula l(ell).
Dennis Williamson
1
(Solaris) -> (Solaris, Sparc), embora Sparc> = V9 seja bi endiano.
Cristian Ciupitu 17/09/10
1
Gostaria de explicar como funciona?
Massimo
Isso parece não funcionar no Android (Nexus 5). Não sei por que ...
wjandrea
printf "\x1" | od -to2 | awk 'NR==1{print$2==1}'
Kaz 25/05
35

Se você estiver em uma máquina Linux bastante recente (quase tudo depois de 2012) , lscpuagora contém essas informações:

$ lscpu | grep Endian
Byte Order:            Little Endian

Isso foi adicionado lscpuna versão 2.19, que é encontrada no Fedora> = 17, CentOS> = 6.0, Ubuntu> = 12.04.

Note que eu encontrei esta resposta a partir de esta resposta óptimo em Unix.SE . Essa resposta tem muitas informações relevantes, este post é apenas um resumo.

dotancohen
fonte
31

Aqui está um script python de uma linha mais elegante

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

código de saída 0significa big endian e 1significa little endian

ou simplesmente mude sys.exitpara printpara uma saída imprimível

mchurichi
fonte
4
Isso não funcionará nos sistemas RHEL 5.x / CentOS 5.x que executam o Python 2.4.x. Aqui está uma correção:python -c "import sys;sys.exit(int(sys.byteorder!='big'))"
JPaget
10

A resposta principal pode ser simplificada levemente usando awk:

Em um sistema Big Endian (Solaris, SPARC)

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

Em um sistema Little Endian (Linux, Intel)

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

Kernels Linux mais recentes

A partir da versão 2.19 do pacote util-linux, o comando lscpucomeçou a incluir um campo relacionado ao Endianness. Então agora você pode simplesmente usar este comando para descobrir isso:

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

Isso foi confirmado no Ubuntu 12.10 e CentOS 6. Portanto, eu estaria disposto a assumir que a maioria dos Kernels do Linux 3.0+ está oferecendo isso agora.

Nos sistemas Debian / Ubuntu, você também pode usar este comando, sem ter certeza de quando ele ficou disponível:

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

Referências

slm
fonte
9

Este script Python deve funcionar para você:

#!/usr/bin/env python
from struct import pack
if pack('@h', 1) == pack('<h', 1):
    print "Little Endian"
else:
    print "Big Endian"
Dennis Williamson
fonte
4
Um forro: python -c "from struct import pack;import sys;sys.exit(int(pack('@h',1)==pack('<h',1)))". O código de saída é 0 para big endian e 1 para little endian.
Cristian Ciupitu 17/09/10
7
python -c "import sys; print(sys.byteorder)"

Seria imprimir a endianess do sistema.

prembhaskal
fonte
6

Você pode tirar proveito do formato de arquivo ELF para determinar a resistência do seu sistema. Por exemplo, imprima os seis primeiros bytes de um arquivo ELF arbitrário em hexadecimal:

xxd -c 1 -l 6 /bin/ls

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

Se a última linha (o byte de seis dígitos) for 01, de acordo com o formato ELF , 01 é little endian e 02 é big endian.

Se você não tiver um xxdna sua caixa (e tiver o busybox), tente o seguinte:

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

Tong Zhou
fonte
Eu acho que você quer dizer um ELF arbitrário ... Como existem outros tipos de executáveis, incluindo shell scripts, perl, python, etc. Mas não dizendo que você está errado, apenas dizendo que vale lembrar que existem outros tipos de executáveis ​​(e por interesse, o código está no segmento de texto, daí o antigo erro de arquivo de texto ocupado).
Pryftan
1
@Pryftan Obrigado por apontar isso. Corrigido!
Tong Zhou
@TongZhou Welcome; Feliz por ajudar!
Pryftan
Impressionante! Primeiro método para trabalhar com sistemas operacionais embarcados baseados em busybox.
Ogurets
3

Eu encontrei uma maneira de fazer isso no Jython. Como o Jython (Python na JVM) é executado em uma VM, ele sempre reporta big endian, independentemente do hardware.

Esta solução funciona para Linux, Solaris, AIX e HPUX. Não testou no Windows:

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

Um comando de linha única baseado no formato ELF:
hexdump -s 5 -n 1 /bin/sh

fae
fonte
Edit: -n 1, desculpe;)
fae
1
Esse é exatamente o mesmo método de uma resposta anterior , que também forneceu mais detalhes que o seu.
kasperd
0

Requisito ligeiramente diferente: preciso de um teste como este em um script de configuração de compilação do programa para determinar se a máquina de destino de compilação é pouco ou pouco endian, sem executar código . O script deve depositar #define HAVE_LITTLE_ENDIAN 1em um config.hcabeçalho, ou então #define HAVE_LITTLE_ENDIAN 0.

A máquina de destino de compilação pode ser diferente da máquina de compilação, pois podemos fazer uma compilação cruzada, o que também explica por que o teste não deve tentar executar nenhum código compilado. Está fora de cogitação ter um pequeno programa C com uma printfdeclaração que cuspa a resposta.

Uma solução possível é essa. Geramos um arquivo chamado conftest.cque contém este:

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

Agora, compilamos isso para conftest.ousar:

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

Então nós corremos:

$ strings conftest.o
PSILXINUEROCMIWD

Se a string PSILXINUEROCMIWDocorrer, o destino é little-endian. Se a string LISPUNIXCOREDWIMocorrer, é big-endian. Se nenhuma string ocorrer ou, ainda mais surpreendente, as duas ocorrerem, o teste falhou.

Essa abordagem funciona porque as constantes "fourcc" calculadas no programa têm valores independentes da máquina, denotando os mesmos números inteiros, independentemente da endianidade. Sua representação de armazenamento no arquivo de objeto segue o endianness do sistema de destino e é visível através da exibição baseada em caracteres em strings.

As duas palavras de proteção zero garantem que a string seja isolada. Isso não é estritamente necessário, mas garante que a sequência que estamos procurando não seja incorporada em outra sequência, o que significa que stringsa saída será feita em uma linha por si só.

PS, a USPELLmacro não coloca parênteses nas inserções de argumento, porque é criada para esse fim específico, não para reutilização.

Kaz
fonte
Não é necessário para todos os projetos, mas o autoconf / automake não possui essa verificação? Meus projetos são sempre pequenos o suficiente para que eu possa criar meus próprios Makefiles (embora nem sempre sejam básicos), então eu realmente não conheço essas ferramentas além de fazer algumas modificações quando necessário e a interface geral ... mas me pergunto se elas têm detecção. Talvez você não precise, mesmo que precise, apenas pensei em jogar fora a possibilidade.
Pryftan