จะรู้ได้อย่างไรว่าระบบลีนุกซ์เป็น endian ใหญ่หรือ endian น้อย?


91

ฉันรู้ว่าโปรเซสเซอร์บางตัวเป็น Big Endian และอื่น ๆ เป็น Little Endian แต่มีคำสั่ง, bash script, python script หรือชุดคำสั่งที่สามารถใช้ที่บรรทัดคำสั่งเพื่อตรวจสอบว่าระบบเป็น Big Endian หรือ Little Endian หรือไม่? สิ่งที่ต้องการ:

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

หรือมันง่ายกว่าที่จะพิจารณาว่าโปรเซสเซอร์ใช้ระบบใดและไปพร้อมกับสิ่งนั้นเพื่อพิจารณา Endianess


นี่คือวิธีการแก้ปัญหาโดยใช้ Perl: stackoverflow.com/questions/2610849/…
slu

คำตอบ:


110

บน Big Endian-System (Solaris บน SPARC)

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

0

บนระบบ endian เล็กน้อย (Linux บน x86)

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

1


วิธีการแก้ปัญหาข้างต้นนั้นฉลาดและใช้งานได้ดีสำหรับ Linux * 86 และ Solaris Sparc

ฉันต้องการโซลูชัน shell-only (ไม่มี Perl) ที่ทำงานบน AIX / Power และ HPUX / Itanium น่าเสียดายที่คนสองคนสุดท้ายเล่นไม่เก่ง: AIX รายงานว่า "6" และ HPUX ให้เส้นที่ว่างเปล่า

ด้วยการใช้โซลูชันของคุณฉันสามารถสร้างบางสิ่งบางอย่างที่ทำงานบนระบบ Unix เหล่านี้ทั้งหมด:

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

เกี่ยวกับโซลูชัน Python ที่โพสต์ไว้จะไม่ทำงานใน Jython เนื่องจาก JVM ถือว่าทุกอย่างเป็นใหญ่ ถ้าใครสามารถทำให้มันใช้งานได้ใน Jython กรุณาโพสต์!

นอกจากนี้ฉันพบสิ่งนี้ซึ่งอธิบายถึง endianness ของแพลตฟอร์มต่างๆ ฮาร์ดแวร์บางตัวสามารถทำงานในโหมดใดโหมดหนึ่งขึ้นอยู่กับสิ่งที่ O / S เลือก: http://labs.hoffmanlabs.com/node/544


หากคุณกำลังจะใช้ awk บรรทัดนี้สามารถทำให้ง่ายขึ้นเพื่อ:

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

สำหรับกล่อง Linux ขนาดเล็กที่ไม่มี 'od' (พูด OpenWrt) ให้ลอง 'hexdump':

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

2
นั่นคือตัวพิมพ์ใหญ่I(ตา) มากกว่าตัวพิมพ์เล็กl(ell)
Dennis Williamson

1
(Solaris) -> (Solaris, Sparc) แม้ว่า Sparc> = V9 คือสอง endian
Cristian Ciupitu

1
สนใจอธิบายว่ามันทำงานอย่างไร?
Massimo

ดูเหมือนว่าจะใช้งานไม่ได้บน Android (Nexus 5) ไม่แน่ใจว่าทำไม ...
wjandrea

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

35

หากคุณอยู่บนเครื่องลีนุกซ์ที่ค่อนข้างใหม่ล่าสุด(เกือบทุกอย่างหลังจากปี 2012)ดังนั้นlscpuตอนนี้จะมีข้อมูลนี้:

$ lscpu | grep Endian
Byte Order:            Little Endian

สิ่งนี้ถูกเพิ่มเข้ามาlscpuในรุ่น 2.19 ซึ่งพบได้ใน Fedora> = 17, CentOS> = 6.0, Ubuntu> = 12.04

โปรดทราบว่าฉันได้พบคำตอบนี้จากคำตอบที่ยอดเยี่ยมนี้ Unix.SE คำตอบนั้นมีข้อมูลที่เกี่ยวข้องมากมายโพสต์นี้เป็นเพียงบทสรุปของมัน


31

นี่คือสคริปต์บรรทัดเดียวของงูใหญ่ที่สง่างามกว่า

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

รหัสการออก0หมายถึง endian ใหญ่และ1หมายถึง endian น้อย

หรือเพียงแค่เปลี่ยนsys.exitไปprintสำหรับการส่งออกที่พิมพ์


4
สิ่งนี้จะไม่ทำงานบนระบบ RHEL 5.x / CentOS 5.x ที่ใช้งาน Python 2.4.x นี่คือการแก้ไข:python -c "import sys;sys.exit(int(sys.byteorder!='big'))"
JPaget

10

คำตอบหลักสามารถทำให้ง่ายขึ้นเล็กน้อยโดยใช้awk:

บนระบบ Big Endian (Solaris, SPARC)

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

บนระบบ Little Endian (Linux, Intel)

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

ใหม่ Linux Kernels

ตั้งแต่เวอร์ชัน 2.19 ของแพ็กเกจ util-linux คำสั่งlscpuเริ่มต้นรวมถึงฟิลด์ที่เกี่ยวข้องกับ Endianness ดังนั้นตอนนี้คุณสามารถใช้คำสั่งนี้เพื่อค้นหา:

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

สิ่งนี้ได้รับการยืนยันบน Ubuntu 12.10 และ CentOS 6 ดังนั้นฉันยินดีที่จะสมมติว่าส่วนใหญ่ 3.0+ Linux Kernels กำลังเสนอสิ่งนี้อยู่

บนระบบ Debian / Ubuntu คุณสามารถใช้คำสั่งนี้ได้เช่นกันไม่แน่ใจว่าเมื่อใดจึงจะพร้อมใช้งาน:

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

อ้างอิง


9

สคริปต์ Python นี้จะทำงานให้คุณ:

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

4
สายการบินหนึ่ง: python -c "from struct import pack;import sys;sys.exit(int(pack('@h',1)==pack('<h',1)))". รหัสทางออกคือ 0 สำหรับ big endian และ 1 สำหรับ endian น้อย
Cristian Ciupitu


6

คุณสามารถใช้ประโยชน์จากรูปแบบไฟล์ของเอลฟ์เพื่อกำหนด endianness ของระบบของคุณ ตัวอย่างเช่นพิมพ์หกไบต์แรกของไฟล์ ELF ตามอำเภอใจในฐานสิบหก:

xxd -c 1 -l 6 /bin/ls

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

หากบรรทัดสุดท้าย (ไบต์ที่หก) เป็น 01 ตามรูปแบบ ELF , 01 คือ endian น้อยและ 02 เป็น endian ใหญ่

หากคุณไม่ได้xxdอยู่ในกล่อง (และมี busybox) ให้ลองทำดังนี้:

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


ฉันคิดว่าคุณหมายถึงเอลฟ์โดยพลการ ... เนื่องจากมีประเภทปฏิบัติการอื่น ๆ รวมถึงเชลล์สคริปต์, Perl, Python, ฯลฯ ไม่ได้บอกว่าคุณผิดอย่างอื่น - เพียงแค่บอกว่ามันคุ้มค่าที่จะจำได้ว่ามีประเภทปฏิบัติการอื่น ๆ เพื่อความสนใจรหัสอยู่ในส่วนของข้อความจึงเกิดข้อผิดพลาดไฟล์ข้อความเก่า)
Pryftan

1
@ Pryftan ขอบคุณที่ชี้ให้เห็น แก้ไขแล้ว!
ตองโจว

@ ตงโจวยินดีต้อนรับ; ดีใจที่ได้ช่วย!
Pryftan

น่ากลัว! วิธีแรกในการทำงานกับระบบปฏิบัติการฝังตัวที่ใช้งานบน busybox
ogurets

3

ฉันพบวิธีที่จะทำใน Jython เนื่องจาก Jython (Python บน JVM) ทำงานบน VM จึงรายงาน endian ใหญ่เสมอโดยไม่คำนึงถึงฮาร์ดแวร์

โซลูชันนี้ใช้ได้กับ Linux, Solaris, AIX และ HPUX ไม่ได้ทดสอบบน Windows:

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


0

ความต้องการที่แตกต่างกันเล็กน้อย: ฉันจำเป็นต้องมีการทดสอบเช่นนี้ในสคริปต์โปรแกรมสร้างการกำหนดค่าเพื่อตรวจสอบว่าเครื่องเป้าหมายรวบรวมเป็นบิตหรือ endian เล็ก ๆ น้อย ๆโดยไม่ต้องดำเนินการรหัส สคริปต์ที่ต้องฝาก#define HAVE_LITTLE_ENDIAN 1เป็นส่วนหัวหรืออื่น ๆconfig.h#define HAVE_LITTLE_ENDIAN 0

เครื่องเป้าหมายการคอมไพล์อาจแตกต่างจากเครื่องบิลด์เนื่องจากเราอาจทำการคอมไพล์ข้ามซึ่งยังอธิบายว่าทำไมการทดสอบจะต้องไม่พยายามรันโค้ดที่คอมไพล์ มันเป็นไปไม่ได้เลยที่จะมีโปรแกรม C นิดหน่อยพร้อมprintfคำสั่งที่คายคำตอบ

ทางออกที่เป็นไปได้คือสิ่งนี้ เราสร้างไฟล์ชื่อconftest.cที่มี:

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

ตอนนี้เรารวบรวมสิ่งนี้เพื่อconftest.oใช้:

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

จากนั้นเราก็เรียกใช้:

$ strings conftest.o
PSILXINUEROCMIWD

หากสตริงPSILXINUEROCMIWDเกิดขึ้นเป้าหมายจะเป็นแบบเอนด์ หากสตริงLISPUNIXCOREDWIMเกิดขึ้นแสดงว่าเป็น big-endian หากไม่มีสตริงเกิดขึ้นหรือน่าประหลาดใจมากกว่ากันทั้งคู่ก็แสดงว่าการทดสอบล้มเหลว

วิธีการนี้ใช้งานได้เพราะค่าคงที่ "fourcc" ที่คำนวณในโปรแกรมมีค่าที่ไม่ขึ้นอยู่กับเครื่อง เป็นตัวแทนของพวกเขาเก็บไว้ในแฟ้มวัตถุดังนี้ endianness stringsของระบบเป้าหมายและที่สามารถมองเห็นได้ผ่านทางมุมมองของตัวอักษรตามภายใต้

คำปกป้องสองคำที่เป็นศูนย์ตรวจสอบให้แน่ใจว่าแยกสตริง นั่นไม่จำเป็นอย่างเคร่งครัด แต่มันทำให้มั่นใจได้ว่าสตริงที่เรากำลังค้นหาไม่ได้ถูกฝังอยู่ในสตริงอื่น ๆ ซึ่งหมายถึงว่าstringsมันจะแสดงผลบนบรรทัดด้วยตัวมันเอง

ป.ล. USPELLแมโครจะไม่วงเล็บการแทรกอาร์กิวเมนต์เนื่องจากสร้างขึ้นเพื่อวัตถุประสงค์เฉพาะนี้ไม่ใช่เพื่อการใช้ซ้ำ


ไม่ใช่ว่าจำเป็นสำหรับทุกโครงการ แต่ autoconf / automake ไม่มีการตรวจสอบนี้หรือไม่? โครงการของฉันมีขนาดเล็กพอที่ฉันสามารถสร้าง Makefiles ของตัวเองได้ (แม้ว่าจะไม่ใช่พื้นฐานเสมอ) ดังนั้นฉันจึงไม่รู้จักเครื่องมือเหล่านั้นนอกจากทำการแก้ไขเมื่อจำเป็นและอินเทอร์เฟซทั่วไป .. แต่ฉันสงสัยว่าพวกมันมีการตรวจจับ บางทีคุณอาจไม่ต้องการมันแม้ว่าจะเป็นเช่นนั้นแค่คิดว่าฉันจะทิ้งความเป็นไปได้
Pryftan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.