ไบนารีเป็นแบบพกพาข้ามสถาปัตยกรรมซีพียูที่แตกต่างกันหรือไม่?


16

เป้าหมายของฉันคือการพัฒนาลินุกซ์ฝังตัว ฉันมีประสบการณ์เกี่ยวกับระบบฝังตัวโลหะเปลือยโดยใช้ ARM

ฉันมีคำถามทั่วไปเกี่ยวกับการพัฒนาสำหรับซีพียูที่แตกต่างกัน คำถามของฉันมีดังนี้:

  1. หากฉันมีแอปพลิเคชันที่คอมไพล์ให้ทำงานบน ' เป้าหมาย x86, linux OS เวอร์ชัน xyz ' ฉันจะสามารถรันไบนารีที่คอมไพล์เดียวกันนี้ในระบบอื่น ' เป้าหมาย ARM, linux OS เวอร์ชัน xyz ' ได้หรือไม่?

  2. หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการรับซอร์สโค้ดของแอปพลิเคชันเพื่อสร้าง / คอมไพล์ซ้ำโดยใช้ toolchain ที่เกี่ยวข้อง 'ตัวอย่างเช่น arm-linux-gnueabi'

  3. ในทำนองเดียวกันถ้าฉันมีโมดูลเคอร์เนลที่สามารถโหลดได้ (ไดรเวอร์อุปกรณ์) ที่ทำงานบน ' x86 เป้าหมาย, linux OS เวอร์ชัน xyz ' ฉันสามารถโหลด / ใช้. ko เดียวกันที่คอมไพล์ได้ในระบบ ' เป้าหมาย ARM, linux OS เวอร์ชัน xyz ' ?

  4. หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการได้รับซอร์สโค้ดไดรเวอร์เพื่อสร้าง / คอมไพล์ใหม่โดยใช้ toolchain ที่เกี่ยวข้อง 'ตัวอย่างเช่น arm-linux-gnueabi'?


27
ไม่ใช่ไม่ใช่ไม่
ฮอบส์

7
มันช่วยให้ตระหนักได้ว่าเราไม่มีเป้าหมายของเอเอ็มดีและเป้าหมายของ Intel เพียงแค่เป้าหมาย x86 เดียวสำหรับทั้งคู่ นั่นเป็นเพราะ Intel และ AMD เข้ากันได้อย่างเพียงพอ จากนั้นจะเห็นได้ชัดว่าเป้าหมาย ARM นั้นมีอยู่ด้วยเหตุผลเฉพาะนั่นคือเนื่องจาก ARM CPU ไม่เข้ากันกับ Intel / AMD / x86
MSalters

1
ไม่เว้นแต่ว่าเป็น bytecode ที่ออกแบบมาให้ทำงานบนสภาพแวดล้อมรันไทม์แบบพกพาเช่น Java Runtime หากคุณกำลังเขียนรหัสเพื่อใช้งานแบบฝังตัวรหัสของคุณจะขึ้นอยู่กับการเพิ่มประสิทธิภาพหรือคุณสมบัติเฉพาะของโปรเซสเซอร์ระดับต่ำและจะยากต่อการพอร์ตซึ่งต้องการมากกว่าการคอมไพล์สำหรับแพลตฟอร์มเป้าหมาย (เช่นการเปลี่ยนรหัสแอสเซมบลี หลายโมดูลหรือทั้งโปรแกรม)
bwDraco

1
@MSalters: ที่จริงแล้วเรามีเป้าหมายของ AMD: amd64 ซึ่งมักจะมีป้ายกำกับ x86-64 (ในขณะที่ x86 มักจะติดฉลากใหม่ของ i386) โชคดีที่ Intel คัดลอก (และขยายภายหลัง) สถาปัตยกรรม AMD ดังนั้น 64 บิต x86 ใด ๆ สามารถเรียกใช้ amd64 ไบนารี
slebetman

คำตอบ:


42

ไม่ไบนารีจะต้องรวบรวมใหม่สำหรับสถาปัตยกรรมเป้าหมายและ Linux ไม่มีอะไรที่เหมือนกับไบนารีไขมันออกจากกล่อง เหตุผลก็คือรหัสรวบรวมไปยังรหัสเครื่องสำหรับสถาปัตยกรรมเฉพาะและรหัสเครื่องนั้นแตกต่างกันมากระหว่างตระกูลโปรเซสเซอร์ส่วนใหญ่ (เช่น ARM และ x86 นั้นแตกต่างกันมาก)

แก้ไข: มันเป็นที่น่าสังเกตว่าบางสถาปัตยกรรมเสนอระดับของความเข้ากันได้ย้อนหลัง (และแม้แต่ยากยิ่งเข้ากันได้กับสถาปัตยกรรมอื่น ๆ ); บน CPU 64 บิตเป็นเรื่องปกติที่จะมีความเข้ากันได้แบบย้อนหลังกับรุ่น 32 บิต (แต่จำไว้ว่า: ไลบรารีที่ต้องพึ่งพาของคุณจะต้องเป็น 32 บิตรวมถึงไลบรารีมาตรฐาน C ของคุณเว้นแต่คุณจะเชื่อมโยงแบบคงที่ ) มูลค่าการกล่าวขวัญก็คือItaniumซึ่งเป็นไปได้ที่จะเรียกใช้รหัส x86 (32- บิตเท่านั้น) แม้ว่าจะช้ามาก ความเร็วในการเรียกใช้ที่ไม่ดีของรหัส x86 นั้นเป็นส่วนหนึ่งของสาเหตุที่ทำให้ตลาดไม่ประสบความสำเร็จ

โปรดจำไว้ว่าคุณยังคงไม่สามารถใช้ไบนารีที่คอมไพล์ด้วยคำแนะนำที่ใหม่กว่าในซีพียูรุ่นเก่าแม้ในโหมดความเข้ากันได้ (ตัวอย่างเช่นคุณไม่สามารถใช้ AVX ในไบนารี่แบบ 32 บิตบนโปรเซสเซอร์ Nehalem x86 ได้ CPU ไม่รองรับ

โปรดทราบว่าโมดูลเคอร์เนลจะต้องรวบรวมสำหรับสถาปัตยกรรมที่เกี่ยวข้อง นอกจากนี้โมดูลเคอร์เนลแบบ 32 บิตจะไม่ทำงานในเมล็ดแบบ 64 บิตหรือในทางกลับกัน

สำหรับข้อมูลเกี่ยวกับไบนารีการคอมไพล์ข้าม (ดังนั้นคุณไม่จำเป็นต้องมี toolchain บนอุปกรณ์ ARM เป้าหมาย) ดูคำตอบที่ครอบคลุมของ grochmal ด้านล่าง


1
มันอาจจะคุ้มค่าที่จะอธิบายเกี่ยวกับความเข้ากันได้ (หรือขาดของมัน) ระหว่าง x86 และ x64 เนื่องจาก x86 ไบนารีบางตัวสามารถทำงานบนแพลตฟอร์ม x64 (ฉันไม่แน่ใจว่านี่เป็นกรณีบน Linux แต่เป็นบน Windows เป็นต้น)
jpmc26

4
@ jpmc26 เป็นไปได้บน Linux; แต่คุณอาจต้องติดตั้งไลบรารีความเข้ากันได้ก่อน รองรับ x86 เป็นส่วนที่ไม่จำเป็นของการติดตั้ง Win64 ใน Linux เป็นตัวเลือก และเพราะโลกของลินุกซ์ไกลออกไปมากขึ้นในการสร้างทุกอย่าง 64 บิตที่มี distros บางตัวไม่ได้เริ่มต้นที่จะติดตั้งไลบรารี่ 32 บิต (ทั้งหมด?) (ฉันไม่แน่ใจว่ามันเป็นเรื่องธรรมดา แต่ได้เห็นบางคำถามเกี่ยวกับเรื่องนี้จากคนที่ใช้ distros กระแสหลักก่อน)
แดนคือเล่นซอโดย Firelight

@ jpmc26 ฉันอัปเดตคำตอบด้วยโน้ตของคุณ; ฉันคิดว่าจะพูดถึงเรื่องนี้ แต่ไม่ต้องการทำให้คำตอบซับซ้อนขึ้น
Elizafox

16

Elizabeth Myers ถูกต้องแต่ละสถาปัตยกรรมต้องใช้ไบนารีที่คอมไพล์สำหรับสถาปัตยกรรมที่มีปัญหา cross-compilerเพื่อสร้างไบนารีสำหรับสถาปัตยกรรมที่แตกต่างจากการทำงานระบบของคุณคุณจำเป็นต้องมี


ในกรณีส่วนใหญ่คุณต้องรวบรวม cross compiler ฉันมีประสบการณ์กับgccเท่านั้น (แต่ฉันเชื่อว่าllvmและคอมไพเลอร์อื่นมีพารามิเตอร์ที่คล้ายกัน) gccข้ามคอมไพเลอร์จะประสบความสำเร็จโดยการเพิ่ม--targetการกำหนดค่า:

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

คุณจำเป็นต้องรวบรวมgcc, glibcและbinutilsมีพารามิเตอร์เหล่านี้ (และให้ส่วนหัวของเคอร์เนลเคอร์เนลที่เครื่องเป้าหมาย)

ในทางปฏิบัติสิ่งนี้มีความซับซ้อนและข้อผิดพลาดในการสร้างแตกต่างกันออกไปมากในระบบที่แตกต่างกัน

มีหลายแนวทางในการรวบรวม toolchain ของ GNU แต่ฉันจะแนะนำLinux From Scratchซึ่งได้รับการดูแลอย่างต่อเนื่องและทำงานได้ดีมากในการอธิบายสิ่งที่คำสั่งที่นำเสนอทำ

ตัวเลือกอื่นคือการคอมไพล์ bootstrap ของ cross-compiler ต้องขอบคุณการต่อสู้รวบรวมคอมไพเลอร์ข้ามไปยังสถาปัตยกรรมที่แตกต่างกันในสถาปัตยกรรมที่แตกต่างกันcrosstool-ngได้ถูกสร้างขึ้น มันให้ bootstrap เหนือ toolchain ที่จำเป็นในการสร้าง cross compiler

crosstool-ngสนับสนุนเป้าหมายสามเท่าในสถาปัตยกรรมที่แตกต่างกันโดยทั่วไปมันเป็นบูทสแตรปที่ผู้คนอุทิศเวลาเพื่อแยกแยะปัญหาที่เกิดขึ้นระหว่างการรวบรวม cross-compiler toolchain


หลาย distros ให้ cross-compilers เป็นแพ็คเกจ:

กล่าวอีกนัยหนึ่งให้ตรวจสอบว่า distro ของคุณมีอะไรบ้างในแง่ของคอมไพเลอร์ข้าม หาก distro ของคุณไม่มี cross compiler สำหรับความต้องการของคุณคุณสามารถรวบรวมได้เสมอ

อ้างอิง:


หมายเหตุเคอร์เนลโมดูล

หากคุณกำลังคอมไพล์ cross-compiler ด้วยมือคุณมีทุกสิ่งที่คุณต้องการในการรวบรวมโมดูลเคอร์เนล glibcนี้เป็นเพราะคุณจะต้องหัวเคอร์เนลที่จะรวบรวม

แต่ถ้าคุณใช้ cross-compiler จาก distro ของคุณคุณจะต้องใช้เคอร์เนลส่วนหัวของเคอร์เนลที่ทำงานบนเครื่องเป้าหมาย


FWIW Fedora มีคอมไพเลอร์ข้ามเช่นกัน
mattdm

@mattdm - ขอบคุณตอบตอบ tweaked ฉันเชื่อว่าฉันได้รับส่วนที่ถูกต้องของ fedora wiki ที่เชื่อมโยง
grochmal

2
เป็นวิธีที่ง่ายกว่าลินุกซ์ตั้งแต่เริ่มต้นที่จะได้รับลินุกซ์และ toolchain crosstool-ngสำหรับสถาปัตยกรรมอีกอย่างก็คือ คุณอาจต้องการเพิ่มเข้าไปในรายการ นอกจากนี้การกำหนดค่าและการคอมไพล์ GNU cross-toolchain ด้วยมือสำหรับสถาปัตยกรรมที่กำหนดนั้นมีส่วนเกี่ยวข้องอย่างเหลือเชื่อและน่าเบื่อยิ่งกว่า--targetธงเพียงอย่างเดียว ฉันสงสัยว่าเป็นส่วนหนึ่งของสาเหตุที่ LLVM ได้รับความนิยม มันได้รับการออกแบบในลักษณะที่คุณไม่จำเป็นต้องสร้างใหม่เพื่อกำหนดเป้าหมายสถาปัตยกรรมอื่น - แต่คุณสามารถกำหนดเป้าหมายหลายแบ็กเอนด์โดยใช้ส่วนหน้าและไลบรารีของเครื่องมือเพิ่มประสิทธิภาพเดียวกัน
Iwillnotexist Idonotexist

@IllnotexistIdonotexist - ขอบคุณฉันได้ tweaked คำตอบเพิ่มเติม ฉันไม่เคยได้ยิน crosstool-ng มาก่อนและมันมีประโยชน์มาก ความคิดเห็นของคุณมีประโยชน์สำหรับฉันมาก
grochmal

9

ทราบว่าเป็นที่พึ่งสุดท้าย (เช่นเมื่อคุณไม่ได้มีรหัสที่มา) คุณสามารถเรียกใช้ไบนารีบนสถาปัตยกรรมที่แตกต่างกันโดยใช้การเลียนแบบชอบqemu,dosboxexagearหรือ อีมูเลเตอร์บางตัวได้รับการออกแบบมาเพื่อเลียนแบบระบบอื่นนอกเหนือจากลินุกซ์ (เช่นdosboxถูกออกแบบมาเพื่อรันโปรแกรม MS-DOS และมีอีมูเลเตอร์จำนวนมากสำหรับเครื่องเล่นเกมยอดนิยม) การจำลองมีค่าใช้จ่ายที่มีประสิทธิภาพอย่างมีนัยสำคัญ: โปรแกรมที่มีการจำลองให้ทำงานช้ากว่าคู่ฉบับดั้งเดิม 2-10 เท่า

หากคุณต้องการเรียกใช้โมดูลเคอร์เนลบน CPU ที่ไม่ใช่เจ้าของภาษาคุณจะต้องจำลองทั้งระบบปฏิบัติการรวมถึงเคอร์เนลสำหรับสถาปัตยกรรมเดียวกัน AFAIK เป็นไปไม่ได้ที่จะรันโค้ดต่างประเทศในเคอร์เนล Linux


3
การปรับความเร็วสำหรับการจำลองมักจะสูงกว่า 10 เท่า แต่หากมีใครพยายามเรียกใช้รหัสที่เขียนขึ้นสำหรับเครื่อง 16Mhz บนเครื่อง 4GHz (250: 1 ที่แตกต่างกันในความเร็ว) เครื่องจำลองที่มีโทษ 50: 1 อาจยังคง เรียกใช้รหัสได้เร็วกว่าที่จะรันบนแพลตฟอร์มเดิม
supercat

7

ไม่เพียง แต่เป็นไบนารีไม่ได้พกพาระหว่าง x86 และ ARM, มีรสชาติที่แตกต่างของ ARM

สิ่งที่คุณน่าจะพบได้ในทางปฏิบัติคือ ARMv6 vs ARMv7 Raspberry Pi 1 คือ ARMv6 รุ่นที่ใหม่กว่าคือ ARMv7 ดังนั้นจึงเป็นไปได้ที่จะรวบรวมรหัสในภายหลังซึ่งไม่สามารถใช้กับ Pi 1 ได้

โชคดีที่ข้อดีอย่างหนึ่งของโอเพ่นซอร์สและซอฟต์แวร์เสรีคือการมีซอร์สเพื่อให้คุณสามารถสร้างใหม่บนสถาปัตยกรรมใด ๆ แม้ว่าสิ่งนี้อาจต้องใช้งานบ้าง

(การกำหนดเวอร์ชันของ ARM ทำให้เกิดความสับสน แต่ถ้ามี V อยู่ก่อนหน้าหมายเลขนั้นจะพูดถึงสถาปัตยกรรมชุดคำสั่ง (ISA) หากไม่มีก็เป็นหมายเลขรุ่นเช่น "Cortex M0" หรือ "ARM926EJS" หมายเลขรุ่นไม่มีอะไรที่จะต้อง ทำอย่างไรกับหมายเลข ISA)


2
... และจากนั้นก็มี subflavors ที่แตกต่างกันสำหรับรสชาติ ARM ที่เหมือนกันและ ABIs ที่แตกต่างกันสำหรับฮาร์ดแวร์เดียวกันที่แน่นอน
Matteo Italia

1
@MatteoItalia Ugh ABIs หลายรายการเป็น snafu เป็นการรักษาสิ่งที่เลวร้ายยิ่งกว่าโรค ARMs บางตัวไม่มีการลงทะเบียน VFP หรือ NEON เลยบางคนมี 16, 32 คนบน Cortex-A8 และก่อนหน้านี้เครื่องยนต์ NEON วิ่ง CC สิบโหลหลังส่วนที่เหลือของแกนดังนั้นการถ่ายโอนเวกเตอร์เอาท์ไปยัง GPR จำนวนมาก ARM ได้รับรอบในการทำสิ่งที่ถูกต้อง - กำหนดชุดย่อยทั่วไปของคุณสมบัติ
Iwillnotexist Idonotexist

7

คุณมักจะต้องกำหนดเป้าหมายแพลตฟอร์ม ในกรณีที่ง่ายที่สุด CPU เป้าหมายจะรันโค้ดที่คอมไพล์โดยตรงในไบนารี่ (ตรงนี้สอดคล้องกับ COM COM ของ MS DOS) ลองพิจารณาสองแพลตฟอร์มที่แตกต่างกันที่ฉันเพิ่งคิดค้น - Armistice และ Intellio ในทั้งสองกรณีเราจะมีโปรแกรม Hello world แบบง่ายที่ให้ผลลัพธ์ 42 บนหน้าจอ ฉันจะสมมติว่าคุณกำลังใช้ภาษาหลายแพลตฟอร์มในลักษณะที่ไม่เชื่อเรื่องพระเจ้าดังนั้นรหัสที่มานั้นเหมือนกันสำหรับทั้งสอง:

Print(42)

บน Armistice คุณมีไดรเวอร์อุปกรณ์ง่าย ๆ ที่ดูแลการพิมพ์ตัวเลขดังนั้นสิ่งที่คุณต้องทำคือส่งออกไปยังพอร์ต ในภาษาแอสเซมบลีแบบพกพาของเราสิ่งนี้จะสอดคล้องกับสิ่งนี้:

out 1234h, 42

อย่างไรก็ตามหรือระบบ Intellio ไม่มีสิ่งนั้นดังนั้นจึงต้องผ่านชั้นอื่น ๆ :

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

โอ๊ะโอเรามีความแตกต่างที่สำคัญระหว่างสองก่อนที่จะถึงรหัสเครื่อง! สิ่งนี้จะสัมพันธ์กับความแตกต่างที่คุณมีระหว่าง Linux และ MS DOS หรือ IBM PC และ X-Box (แม้ว่าทั้งสองอาจใช้ CPU เดียวกัน)

แต่นั่นคือสิ่งที่ระบบปฏิบัติการใช้ สมมติว่าเรามี HAL ที่ทำให้แน่ใจว่าการกำหนดค่าฮาร์ดแวร์ที่แตกต่างกันทั้งหมดได้รับการจัดการในลักษณะเดียวกันกับเลเยอร์แอปพลิเคชัน - โดยทั่วไปเราจะใช้วิธี Intellio แม้ใน Armistice และรหัส "ชุดประกอบแบบพกพา" ของเราก็จบลงด้วยเหมือนกัน สิ่งนี้ถูกใช้โดยทั้งระบบ Unix ที่ทันสมัยและ Windows บ่อยครั้งแม้ในสถานการณ์แบบฝังตัว ดี - ตอนนี้เราสามารถมีรหัสแอสเซมบลีแบบพกพาตัวเดียวกันได้ทั้งบน Armistice และ Intellio แต่แล้วไบนารีล่ะ

ดังที่เราได้สันนิษฐานไว้ซีพียูจะต้องดำเนินการไบนารีโดยตรง ลองดูบรรทัดแรกของรหัสของเราmov a, 10hบน Intellio:

20 10

โอ้ ปรากฎว่าmov a, constantเป็นที่นิยมมากมันมีคำสั่งของตัวเองด้วย opcode ของตัวเอง Armistice จัดการกับสิ่งนี้อย่างไร

36 01 00 10

อืมมม มีรหัสสำหรับmov.reg.immเราจึงต้องมีอาร์กิวเมนต์อื่นเพื่อเลือกการลงทะเบียนที่เรากำหนดให้ และค่าคงที่นั้นมีขนาด 2 ไบต์เสมอในเครื่องหมายใหญ่ - นั่นคือวิธีที่ Armistice ได้รับการออกแบบในความเป็นจริงคำแนะนำทั้งหมดใน Armistice มีความยาว 4 ไบต์ไม่มีข้อยกเว้น

ตอนนี้คิดทำงานไบนารีจาก Intellio ในศึก: CPU ที่จะเริ่มต้นการถอดรหัสการเรียนการสอนพบว่า 20hopcode บน Armistice สิ่งนี้สอดคล้องกับand.imm.regคำสั่ง มันพยายามที่จะอ่านค่าคงที่คำ 2 ไบต์ (ซึ่งอ่าน10XXแล้วมีปัญหา) และจากนั้นหมายเลขทะเบียน (อื่นXX ) เรากำลังดำเนินการคำสั่งที่ไม่ถูกต้องโดยมีข้อโต้แย้งที่ผิด และที่แย่กว่านั้นคือคำสั่งถัดไปจะเป็นการปลอมแบบสมบูรณ์เพราะเรากินคำสั่งอื่นจริง ๆ แล้วคิดว่ามันเป็นข้อมูล

แอปพลิเคชันไม่มีโอกาสทำงานและมีแนวโน้มว่าจะเกิดข้อผิดพลาดหรือแฮงค์เกือบจะในทันที

ตอนนี้ไม่ได้หมายความว่าผู้ปฏิบัติการต้องบอกว่ามันทำงานบน Intellio หรือ Armistice คุณเพียงแค่ต้องกำหนดแพลตฟอร์มที่เป็นอิสระจาก CPU (เช่นbashUnix) หรือทั้ง CPU และ OS (เช่น Java หรือ. NET และในปัจจุบันแม้แต่ JavaScript ก็เป็นชนิด) ในกรณีนี้แอปพลิเคชันสามารถใช้หนึ่งไฟล์ปฏิบัติการสำหรับซีพียูและระบบปฏิบัติการที่แตกต่างกันทั้งหมดในขณะที่มีแอพพลิเคชั่นหรือบริการบางอย่างบนระบบเป้าหมาย (ซึ่งกำหนดเป้าหมาย CPU และ / หรือระบบปฏิบัติการที่ถูกต้องโดยตรง) CPU สามารถดำเนินการได้จริง สิ่งนี้อาจหรือไม่มาพร้อมกับประสิทธิภาพค่าใช้จ่ายหรือความสามารถ

ซีพียูมักจะมาในครอบครัว ตัวอย่างเช่นซีพียูทั้งหมดจากตระกูล x86 มีชุดคำสั่งทั่วไปที่เข้ารหัสในแบบเดียวกันดังนั้นซีพียู x86 ทุกตัวสามารถเรียกใช้โปรแกรม x86 ได้ทุกโปรแกรมตราบใดที่ไม่ได้พยายามใช้ส่วนขยายใด ๆ (ตัวอย่างเช่น การดำเนินการเกี่ยวกับทศนิยมหรือการดำเนินการเวกเตอร์) ใน x86 ตัวอย่างที่พบบ่อยที่สุดในวันนี้คือ Intel และ AMD แน่นอน Atmel เป็น บริษัท ที่รู้จักกันดีในการออกแบบซีพียูในตระกูล ARM ซึ่งค่อนข้างเป็นที่นิยมสำหรับอุปกรณ์ฝังตัว แอปเปิ้ลยังมีซีพียู ARM ของตัวเองเช่น

แต่ ARM นั้นเข้ากันไม่ได้กับ x86 อย่างเต็มที่ - พวกเขามีความต้องการการออกแบบที่แตกต่างกันมากและมีความเหมือนกันเล็กน้อย คำแนะนำนั้นมีรหัสที่แตกต่างกันอย่างสิ้นเชิงพวกมันถูกถอดรหัสในลักษณะที่แตกต่างกันที่อยู่หน่วยความจำได้รับการปฏิบัติที่แตกต่างกัน ... มันอาจเป็นไปได้ที่จะสร้างไบนารีที่ทำงานทั้งในซีพียู x86 และซีพียู ARM แยกความแตกต่างระหว่างคำสั่งทั้งสองและกระโดดไปที่ชุดคำสั่งที่แตกต่างกันสองชุด แต่ก็ยังหมายความว่าคุณมีคำสั่งแยกต่างหากสำหรับทั้งสองรุ่น


3

เป็นไปได้ที่จะส่งคำถามนี้ซ้ำอีกครั้งในสภาพแวดล้อมที่อาจคุ้นเคยมากกว่า โดยการเปรียบเทียบ:

"ฉันมีโปรแกรม Ruby ที่ฉันต้องการรัน แต่แพลตฟอร์มของฉันมีล่าม Python เท่านั้นฉันสามารถใช้ Python interpreter เพื่อรันโปรแกรม Ruby ของฉันหรือฉันต้องเขียนโปรแกรมของฉันใน Python ใหม่"

สถาปัตยกรรมชุดคำสั่ง ("เป้าหมาย") เป็นภาษา - "ภาษาเครื่อง" - และ CPU ที่แตกต่างกันใช้ภาษาที่แตกต่างกัน ดังนั้นการขอให้ซีพียู ARM ใช้งานไบนารีของ Intel นั้นเป็นเหมือนการพยายามรันโปรแกรม Ruby โดยใช้ล่ามภาษาไพ ธ อน


2

gcc ใช้คำว่า '' architecture '' เพื่อหมายถึง '' ชุดคำสั่ง '' ของ CPU เฉพาะและ "เป้าหมาย" ครอบคลุมการรวมกันของ CPU และสถาปัตยกรรมพร้อมกับตัวแปรอื่น ๆ เช่น ABI, libc, endian-ness และอื่น ๆ (อาจรวมถึง "โลหะเปลือย") คอมไพเลอร์ทั่วไปมีชุดเป้าหมาย จำกัด (อาจเป็นหนึ่ง ABI, หนึ่งตระกูล CPU แต่อาจเป็นได้ทั้ง 32- และ 64- บิต) ข้ามคอมไพเลอร์มักจะหมายถึงทั้งคอมไพเลอร์ที่มีเป้าหมายอื่นที่ไม่ใช่ระบบจะทำงานบนหรือหนึ่งที่มีเป้าหมายหลายหรือ ABIs (ดูยังนี้ )

ไบนารีเป็นแบบพกพาข้ามสถาปัตยกรรมซีพียูที่แตกต่างกันหรือไม่?

โดยทั่วไปไม่มี ไบนารีในแง่ทั่วไปคือรหัสวัตถุดั้งเดิมสำหรับซีพียูหรือตระกูลซีพียูโดยเฉพาะ แต่มีหลายกรณีที่สามารถพกพาได้ในระดับปานกลาง:

  • สถาปัตยกรรมหนึ่งคือซูเปอร์เซ็ตของอีกสถาปัตยกรรมหนึ่ง (โดยทั่วไปคือ x86 ไบนารีเป้าหมาย i386 หรือ i686 แทนที่จะเป็น x86 ล่าสุดและยิ่งใหญ่ที่สุดเช่น-march=core2)
  • สถาปัตยกรรมหนึ่งจัดเตรียมการเลียนแบบดั้งเดิมหรือการแปลของอีกสถาปัตยกรรมหนึ่ง (คุณอาจเคยได้ยินCrusoe ) หรือมีโปรเซสเซอร์ร่วมที่เข้ากันได้ (เช่นPS2 )
  • ระบบปฏิบัติการและรันไทม์สนับสนุนmultiarch (เช่นความสามารถในการเรียกใช้ไบนารี x86 แบบ 32 บิตบน x86_64) หรือทำให้ VM / JIT เป็นไปอย่างราบรื่น (Android โดยใช้DalvikหรือART )
  • มีการรองรับไบนารี "อ้วน" ที่มีรหัสซ้ำกันสำหรับสถาปัตยกรรมที่สนับสนุนแต่ละรายการ

หากคุณจัดการเพื่อแก้ไขปัญหานี้อย่างใดปัญหาไบนารีแบบพกพาอื่น ๆของรุ่นห้องสมุดมากมาย (glibc ฉันกำลังมองคุณ) จะนำเสนอตัวเอง (ระบบฝังตัวส่วนใหญ่ช่วยให้คุณประหยัดจากปัญหานั้นอย่างน้อย)

หากคุณยังไม่ได้ตอนนี้เป็นเวลาที่ดีในการทำงานgcc -dumpspecsและgcc --target-helpดูว่าคุณกำลังทำอะไรอยู่

ไบนารีไขมันมีข้อเสียต่าง ๆแต่ก็ยังมีการใช้ที่เป็นไปได้ ( EFI )

อย่างไรก็ตามยังมีข้อควรพิจารณาอีกสองประการที่หายไปจากคำตอบอื่น ๆ : ELF และล่าม ELF และการสนับสนุนเคอร์เนล Linux สำหรับรูปแบบไบนารีโดยอำเภอใจ ฉันจะไม่ไปลงรายละเอียดเกี่ยวกับไบนารีหรือ bytecode สำหรับการประมวลผลที่ไม่จริงที่นี่แม้ว่ามันจะเป็นไปได้ในการรักษาเหล่านี้เป็น "แม่" และรัน Java หรือรวบรวมงูหลามไบนารี bytecodeไบนารีดังกล่าวมีความเป็นอิสระของสถาปัตยกรรมฮาร์ดแวร์ ( แต่ขึ้นอยู่แทน บนเวอร์ชัน VM ที่เกี่ยวข้องซึ่งในที่สุดจะรันไบนารีดั้งเดิม)

ระบบลีนุกซ์ร่วมสมัยใด ๆ จะใช้ ELF ไบนารี (รายละเอียดทางเทคนิคใน PDF นี้ ) ในกรณีของไบนารี ELF แบบไดนามิกเคอร์เนลจะรับผิดชอบในการโหลดภาพลงในหน่วยความจำ แต่มันเป็นงานของชุด '' ล่าม 'ใน ELF ส่วนหัวที่จะทำการยกของหนัก ปกตินี้เกี่ยวข้องกับการทำให้แน่ใจว่าทุกห้องสมุดแบบไดนามิกขึ้นอยู่กับที่มีอยู่ (ด้วยความช่วยเหลือของ '' ไดนามิค '' ส่วนที่รายการห้องสมุดและบางส่วนโครงสร้างอื่น ๆ ซึ่งรายการสัญลักษณ์ที่กำหนด) - แต่นี้เป็นเกือบชั้นร้ายอเนกประสงค์

$ 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.2ยังเป็นไบนารีของเอลฟ์มันไม่มีล่ามและเป็นรหัสไบนารี่ดั้งเดิม)

ปัญหากับ ELF คือส่วนหัวในไบนารี ( readelf -h /bin/ls) ทำเครื่องหมายสำหรับสถาปัตยกรรมเฉพาะคลาส (32- หรือ 64- บิต), endian-ness และ ABI (ไบนารีไขมัน "สากล" ของ Apple ใช้รูปแบบไบนารีสำรองMach-Oซึ่งจะแก้ปัญหานี้ซึ่งมาจาก NextSTEP) ซึ่งหมายความว่าเอลฟ์ที่ปฏิบัติการได้จะต้องตรงกับระบบที่จะใช้งาน หนึ่งฟักหนีเป็นล่ามซึ่งสามารถปฏิบัติการใด ๆ (รวมถึงหนึ่งที่แยกหรือแมปส่วนย่อยสถาปัตยกรรมที่เฉพาะเจาะจงของไบนารีเดิมและเรียกพวกเขา) แต่คุณยังคงถูก จำกัด โดยประเภทของเอลฟ์ระบบของคุณจะอนุญาตให้เรียกใช้ . (FreeBSD มีวิธีที่น่าสนใจในการจัดการไฟล์ Linux ELFซึ่งbrandelfจะแก้ไขฟิลด์ ELF ABI)

มีการสนับสนุน (โดยใช้binfmt_misc) สำหรับ Mach-O บน linuxมีตัวอย่างที่แสดงวิธีการสร้างและเรียกใช้ไบนารี (32- & 64- บิต) ไขมัน Resource forks / ADSซึ่งเดิมทำบน Mac อาจเป็นวิธีแก้ปัญหา แต่ไม่มีระบบไฟล์ Linux ดั้งเดิมที่รองรับสิ่งนี้

สิ่งเดียวกันนี้มีผลกับโมดูลเคอร์เนล แต่.koไฟล์ก็ยังเป็น ELF เช่นกัน (แม้ว่าพวกเขาจะไม่มีชุดล่าม) ในกรณีนี้มีเลเยอร์พิเศษซึ่งใช้เคอร์เนลเวอร์ชัน ( uname -r) ในเส้นทางการค้นหาสิ่งที่สามารถทำได้ในทางทฤษฎีแทนใน ELF ด้วยการกำหนดเวอร์ชัน แต่มีความซับซ้อนและได้รับเล็กน้อยฉันสงสัยว่า

ตามที่ระบุไว้ในที่อื่น, Linux ไม่รองรับไบนารีไขมัน แต่มีโครงการไขมันไบนารีที่ active: FatELF มีมานานหลายปีแล้วและไม่เคยรวมเข้ากับเคอร์เนลมาตรฐานส่วนหนึ่งเนื่องมาจากข้อกังวลด้านสิทธิบัตร (หมดอายุแล้ว) ในเวลานี้มันต้องการทั้งเคอร์เนลและ toolchain สนับสนุน มันไม่ได้ใช้binfmt_miscวิธีการนี้เป็นขั้นตอนด้านปัญหาส่วนหัวของ ELF และอนุญาตให้โมดูลเคอร์เนลไขมันเกินไป

  1. หากฉันมีแอพพลิเคชั่นที่คอมไพล์ให้ทำงานบน 'x86 target, linux OS version xyz', ฉันจะสามารถรันไบนารีที่คอมไพล์เดียวกันบนระบบอื่น 'เป้าหมาย ARM, linux OS เวอร์ชัน xyz' ได้หรือไม่?

ไม่ใช่กับเอลฟ์มันจะไม่ยอมให้คุณทำเช่นนี้

  1. หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการรับซอร์สโค้ดของแอปพลิเคชันเพื่อสร้าง / คอมไพล์ซ้ำโดยใช้ toolchain ที่เกี่ยวข้อง 'ตัวอย่างเช่น arm-linux-gnueabi'

คำตอบง่ายๆคือใช่ (คำตอบที่ซับซ้อนรวมถึงการเลียนแบบการเป็นตัวแทนระดับกลางนักแปลและ JIT ยกเว้นกรณีของ "การลดระดับ" ไบนารี i686 เพื่อใช้เฉพาะ opcodes i386 เท่านั้นพวกเขาอาจไม่น่าสนใจที่นี่และการแก้ไข ABI นั้นอาจเป็นเรื่องยาก )

  1. ในทำนองเดียวกันถ้าฉันมีโมดูลเคอร์เนลที่สามารถโหลดได้ (ไดรเวอร์อุปกรณ์) ที่ทำงานบน 'x86 เป้าหมาย, linux OS เวอร์ชัน xyz' ฉันสามารถโหลด / ใช้. ko เดียวกันที่คอมไพล์ได้ในระบบ 'เป้าหมาย ARM, linux OS เวอร์ชัน xyz' ?

ไม่เอลฟ์จะไม่ยอมให้คุณทำเช่นนี้

  1. หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการได้รับซอร์สโค้ดไดรเวอร์เพื่อสร้าง / คอมไพล์ใหม่โดยใช้ toolchain ที่เกี่ยวข้อง 'ตัวอย่างเช่น arm-linux-gnueabi'?

คำตอบง่ายๆคือใช่ ฉันเชื่อว่า FatELF ช่วยให้คุณสร้างสิ่ง.koที่มีหลายสถาปัตยกรรมได้ แต่ในบางจุดต้องสร้างรุ่นไบนารีสำหรับทุกสถาปัตยกรรมที่รองรับ สิ่งที่ต้องใช้โมดูลเคอร์เนลมักจะมาพร้อมกับแหล่งที่มาและสร้างตามที่ต้องการเช่น VirtualBox ทำเช่นนี้

คำตอบนี้เป็นคำตอบที่ยาวแล้วมีทางอ้อมอีกหนึ่งทางเท่านั้น เคอร์เนลแล้วมีเครื่องเสมือนที่สร้างขึ้นในแม้ว่าเฉพาะหนึ่งที่: BPF VMซึ่งจะใช้เพื่อให้ตรงกับแพ็คเก็ต มนุษย์สามารถอ่านได้กรอง "foo โฮสต์และไม่พอร์ต 22") จะรวบรวมไป bytecode และเคอร์เนลแพ็คเก็ตตัวกรองรันมัน eBPFใหม่นั้นไม่ได้มีไว้สำหรับแพ็คเก็ตเท่านั้นในทางทฤษฎีแล้วโค้ด VM นั้นสามารถพกพาไปยัง linux ร่วมสมัยได้และllvm ก็รองรับมันแต่ด้วยเหตุผลด้านความปลอดภัยมันอาจจะไม่เหมาะกับสิ่งอื่นใด


ตอนนี้ขึ้นอยู่กับความใจกว้างของคุณกับคำจำกัดความของไบนารีที่ปฏิบัติการได้คุณสามารถ (ab) binfmt_miscเพื่อใช้การสนับสนุนไบนารีไขมันด้วยเชลล์สคริปต์และไฟล์ ZIP เป็นรูปแบบคอนเทนเนอร์:

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

เรียกสิ่งนี้ว่า "wozbin" แล้วตั้งค่าด้วย:

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

สิ่งนี้ลงทะเบียน.wozไฟล์ด้วยเคอร์เนลwozbinสคริปต์ถูกเรียกใช้แทนโดยมีอาร์กิวเมนต์แรกตั้งเป็นพา ธ ของ.wozไฟล์ที่ถูกเรียกใช้

หากต้องการรับไฟล์พกพา.woz เพียงสร้างtest.wozไฟล์ ZIP พร้อมลำดับชั้นไดเรกทอรี

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

ภายในแต่ละไดเร็กทอรี arch / OS / libc (ตัวเลือกเอง) วางtestไบนารีเฉพาะสถาปัตยกรรมและคอมโพเนนต์เช่น.soไฟล์ เมื่อคุณเรียกใช้ไดเรกทอรีย่อยที่ต้องการจะถูกแยกไปยังระบบไฟล์ในหน่วยความจำ tmpfs (ที่/mnt/tmpfsนี่) และเรียกใช้


0

berry boot, แก้ปัญหาของคุณบ้าง .. แต่มันไม่แก้ปัญหาวิธีการรันบน arm hf, normall / regullAr linux distro สำหรับ x86-32 / 64 บิต

ฉันคิดว่ามันควรจะสร้างขึ้นใน isolinux (boatloader linux บน usb) บางตัวแปลงสดสิ่งที่สามารถจำ distullar distro และในการขี่ / แปลงสดเป็น hf

ทำไม? เพราะหากแต่ละลินุกซ์สามารถถูกแปลงโดย berry boot เพื่อทำงานบน arm-hf ดังนั้นมันสามารถสร้างกลไก bery boot เพื่อแยกสิ่งที่เราบูทใช้สำหรับ exaple eacher หรือ build ในอูบุนตู creat เริ่มต้นขึ้นบนดิสก์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.