Các nhị phân có thể di động trên các kiến ​​trúc CPU khác nhau không?


16

Mục tiêu của tôi là có thể phát triển cho Linux nhúng. Tôi có kinh nghiệm về các hệ thống nhúng kim loại trần bằng ARM.

Tôi có một số câu hỏi chung về việc phát triển cho các mục tiêu cpu khác nhau. Câu hỏi của tôi như sau:

  1. Nếu tôi có một ứng dụng được biên dịch để chạy trên ' x86 đích, phiên bản hệ điều hành linux xyz ', tôi có thể chạy cùng một nhị phân được biên dịch trên hệ thống khác ' ARM đích, phiên bản hệ điều hành linux xyz ' không?

  2. Nếu ở trên là không đúng, cách duy nhất là lấy mã nguồn ứng dụng để xây dựng lại / biên dịch lại bằng cách sử dụng chuỗi công cụ có liên quan 'ví dụ: arm-linux-gnueabi'?

  3. Tương tự như vậy, nếu tôi có một mô-đun hạt nhân có thể nạp được (trình điều khiển thiết bị) mà công trình trên ' mục tiêu x86, Linux OS phiên bản xyz ', tôi có thể chỉ tải / sử dụng cùng một biên soạn .ko trên một hệ thống ' mục tiêu ARM, Linux OS phiên bản xyz ' ?

  4. Nếu ở trên là không đúng, cách duy nhất là lấy mã nguồn trình điều khiển để xây dựng lại / biên dịch lại bằng cách sử dụng chuỗi công cụ có liên quan ', ví dụ: arm-linux-gnueabi'?


27
không, có, không, có
hobbs

7
Điều này giúp nhận ra rằng chúng tôi không có mục tiêu AMD và mục tiêu Intel, chỉ là một mục tiêu x86 cho cả hai. Đó là bởi vì Intel và AMD tương thích đủ. Sau đó, rõ ràng là mục tiêu ARM tồn tại vì một lý do cụ thể, cụ thể là vì CPU ARM không tương thích với Intel / AMD / x86.
MSalters

1
Không, trừ khi mã byte được thiết kế để chạy trên môi trường thời gian chạy di động như Java Runtime. Nếu bạn đang viết mã để sử dụng nhúng, mã của bạn có thể sẽ dựa vào các tính năng hoặc tối ưu hóa dành riêng cho bộ xử lý cấp thấp và sẽ rất khó chuyển, yêu cầu nhiều hơn là chỉ biên dịch cho nền tảng đích (ví dụ: thay đổi mã lắp ráp, có thể viết lại một số mô-đun hoặc toàn bộ chương trình).
bwDraco - Phục hồi Monica

1
@MSalters: Trên thực tế, chúng tôi có một mục tiêu AMD: amd64 thường được gắn nhãn x86-64 (trong khi x86 thường là nhãn lại của i386). May mắn thay, Intel đã sao chép (và sau đó mở rộng) kiến ​​trúc AMD để bất kỳ x86 64 bit nào cũng có thể chạy nhị phân amd64.
slebetman

Câu trả lời:


42

Số nhị phân phải được (biên dịch lại) cho kiến ​​trúc đích và Linux không cung cấp gì giống như mã nhị phân ngoài hộp. Lý do là vì mã được biên dịch thành mã máy cho một kiến ​​trúc cụ thể và mã máy rất khác nhau giữa hầu hết các họ bộ xử lý (ví dụ ARM và x86 rất khác nhau).

EDIT: đáng chú ý là một số kiến ​​trúc cung cấp các mức độ tương thích ngược (và thậm chí hiếm hơn, tương thích với các kiến ​​trúc khác); trên CPU 64 bit, thông thường có khả năng tương thích ngược với phiên bản 32 bit (nhưng hãy nhớ: thư viện phụ thuộc của bạn cũng phải là 32 bit, bao gồm thư viện chuẩn C của bạn, trừ khi bạn liên kết tĩnh ). Một điều đáng nói nữa là Itanium , nơi có thể chạy mã x86 (chỉ 32 bit), mặc dù rất chậm; tốc độ thực thi kém của mã x86 ít nhất là một phần lý do khiến nó không thành công trên thị trường.

Xin lưu ý rằng bạn vẫn không thể sử dụng các tệp nhị phân được biên dịch theo hướng dẫn mới hơn trên CPU cũ hơn, ngay cả trong các chế độ tương thích (ví dụ: bạn không thể sử dụng AVX trong tệp nhị phân 32 bit trên bộ xử lý Nehalem x86 ; CPU chỉ không hỗ trợ nó.

Lưu ý rằng các mô-đun hạt nhân phải được biên dịch cho kiến ​​trúc có liên quan; Ngoài ra, các mô-đun hạt nhân 32 bit sẽ không hoạt động trên các hạt nhân 64 bit hoặc ngược lại.

Để biết thông tin về các nhị phân biên dịch chéo (vì vậy bạn không cần phải có một chuỗi công cụ trên thiết bị ARM mục tiêu), hãy xem câu trả lời toàn diện của grochmal bên dưới.


1
Có thể đáng làm rõ về bất kỳ khả năng tương thích (hoặc thiếu nào) giữa x86 và x64, với điều kiện một số nhị phân x86 có thể chạy trên nền tảng x64. (Tôi không chắc đây là trường hợp của Linux, nhưng nó là trên Windows chẳng hạn.)
jpmc26

4
@ jpmc26 có thể có trên Linux; nhưng bạn có thể cần cài đặt thư viện tương thích trước. Hỗ trợ x86 là một phần không bắt buộc trong cài đặt Win64. Trong Linux, nó là tùy chọn; và bởi vì thế giới Linux xa hơn rất nhiều trong việc tạo ra các phiên bản 64 bit của mọi thứ có sẵn, một số bản phân phối không mặc định có các thư viện 32 bit (tất cả?) được cài đặt. (Tôi không chắc mức độ phổ biến của nó; nhưng đã thấy một vài truy vấn về nó từ những người chạy các bản phân phối chính thống trước đây.)
Dan Neely

@ jpmc26 Tôi đã cập nhật câu trả lời của tôi với ghi chú của bạn; Tôi nghĩ về việc đề cập đến điều đó nhưng không muốn làm phức tạp câu trả lời.
Hà Lan

16

Elizabeth Myers là chính xác, mỗi kiến ​​trúc đòi hỏi một nhị phân biên dịch cho kiến ​​trúc được đề cập. Để xây dựng nhị phân cho một kiến ​​trúc khác với hệ thống của bạn chạy trên bạn cần a cross-compiler.


Trong hầu hết các trường hợp, bạn cần biên dịch một trình biên dịch chéo. Tôi chỉ có kinh nghiệm với gcc(nhưng tôi tin rằng llvm, và các trình biên dịch khác, có các tham số tương tự). Một gcctrình biên dịch chéo đạt được bằng cách thêm --targetvào cấu hình:

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

Bạn cần phải biên dịch gcc, glibcbinutilsvới các thông số này (và cung cấp tiêu đề hạt nhân của hạt nhân tại máy mục tiêu).

Trong thực tế, điều này phức tạp hơn đáng kể và các lỗi xây dựng khác nhau xuất hiện trên các hệ thống khác nhau.

Có một số hướng dẫn về cách biên dịch chuỗi công cụ GNU nhưng tôi sẽ đề xuất Linux From Scratch , được duy trì liên tục và thực hiện rất tốt việc giải thích các lệnh được trình bày làm gì.

Một tùy chọn khác là một trình biên dịch bootstrap của trình biên dịch chéo. Nhờ vào cuộc đấu tranh biên dịch chéo cho các kiến ​​trúc khác nhau trên các kiến ​​trúc khác nhau crosstool-ngđã được tạo ra. Nó cung cấp một bootstrap trên toolchain cần thiết để xây dựng một trình biên dịch chéo.

crosstool-nghỗ trợ một số bộ ba mục tiêu trên các kiến ​​trúc khác nhau, về cơ bản nó là một bootstrap nơi mọi người dành thời gian để sắp xếp các vấn đề xảy ra trong quá trình biên dịch chuỗi công cụ biên dịch chéo.


Một số bản phân phối cung cấp trình biên dịch chéo dưới dạng gói:

Nói cách khác, kiểm tra xem bản phân phối của bạn có sẵn về mặt trình biên dịch chéo. Nếu bản phân phối của bạn không có trình biên dịch chéo cho nhu cầu của bạn, bạn luôn có thể tự biên dịch nó.

Người giới thiệu:


Mô-đun hạt nhân lưu ý

Nếu bạn đang biên dịch trình biên dịch chéo của mình bằng tay, bạn có mọi thứ bạn cần để biên dịch các mô-đun hạt nhân. Điều này là do bạn cần các tiêu đề kernel để biên dịch glibc.

Nhưng, nếu bạn đang sử dụng trình biên dịch chéo do distro cung cấp, bạn sẽ cần các tiêu đề kernel của kernel chạy trên máy đích.


FWIW Fedora cũng bao gồm các trình biên dịch chéo.
mattdm

@mattdm - cảm ơn, câu trả lời đã được điều chỉnh, tôi tin rằng tôi đã có phần đúng của wiki fedora được liên kết.
hóa học

2
Một cách dễ dàng hơn Linux From Scratch để có được Linux và toolchain cho kiến ​​trúc khác là crosstool-ng. Bạn có thể muốn thêm nó vào danh sách. Ngoài ra, việc cấu hình và biên dịch chuỗi công cụ chéo GNU bằng tay cho bất kỳ kiến ​​trúc cụ thể nào có liên quan đến mức độ đáng kinh ngạc và tẻ nhạt hơn nhiều so với chỉ các --targetcờ. Tôi nghi ngờ đó là một phần lý do tại sao LLVM đang trở nên phổ biến; Nó được kiến ​​trúc theo cách mà bạn không cần xây dựng lại để nhắm mục tiêu kiến ​​trúc khác - thay vào đó bạn có thể nhắm mục tiêu nhiều phụ trợ bằng cách sử dụng cùng một thư viện tối ưu hóa và lối vào.
Idonotexist Idonotexist

@IwillnotexistIdonotexist - cảm ơn, tôi đã điều chỉnh câu trả lời thêm. Tôi chưa bao giờ nghe nói về crosstool-ng trước đây, và nó có vẻ rất hữu ích. Nhận xét của bạn đã thực sự hữu ích cho tôi.
grochmal

9

Lưu ý rằng như là phương sách cuối cùng (nghĩa là khi bạn không có mã nguồn), bạn có thể chạy nhị phân trên một kiến ​​trúc khác bằng cách sử dụng trình giả lập như qemu, dosboxhoặc exagear. Một số trình giả lập được thiết kế để mô phỏng các hệ thống khác ngoài Linux (ví dụ: dosboxđược thiết kế để chạy các chương trình MS-DOS và có rất nhiều trình giả lập cho các máy chơi game phổ biến). Thi đua có chi phí hoạt động đáng kể: các chương trình mô phỏng chạy chậm hơn 2-10 lần so với các đối tác bản địa của chúng.

Nếu bạn cần chạy các mô-đun hạt nhân trên CPU không có nguồn gốc, bạn sẽ phải mô phỏng toàn bộ HĐH bao gồm cả nhân cho cùng một kiến ​​trúc. AFAIK không thể chạy mã nước ngoài trong nhân Linux.


3
Hình phạt tốc độ cho giả lập thường cao hơn gấp 10 lần, nhưng nếu một người đang cố chạy mã được viết cho máy 16Mhz trên máy 4GHz (tốc độ chênh lệch 250: 1) thì trình giả lập có hình phạt tốc độ 50: 1 vẫn có thể chạy mã nhanh hơn nhiều so với chạy trên nền tảng ban đầu.
supercat

7

Không chỉ các nhị phân không di động giữa x86 và ARM, còn có các hương vị khác nhau của ARM .

Người bạn có thể gặp trong thực tế là ARMv6 vs ARMv7. Raspberry Pi 1 là ARMv6, phiên bản mới hơn là ARMv7. Vì vậy, có thể biên dịch mã trên các mã sau không hoạt động trên Pi 1.

May mắn thay, một lợi ích của nguồn mở và phần mềm miễn phí là có nguồn để bạn có thể xây dựng lại nó trên bất kỳ kiến ​​trúc nào. Mặc dù điều này có thể yêu cầu một số công việc.

(Phiên bản ARM khó hiểu, nhưng nếu có chữ V trước số thì nó nói về kiến ​​trúc tập lệnh (ISA). Nếu không, đó là số kiểu như "Cortex M0" hoặc "ARM926EJS". Số mô hình không có gì để làm với số ISA.)


2
... Và sau đó, thậm chí còn có các phân vùng khác nhau cho cùng một hương vị ARM và thậm chí các ABI khác nhau cho cùng một phần cứng (Tôi đang nghĩ về toàn bộ mớ hỗn độn điểm mềm / mềm / mềm ARM).
Matteo Italia

1
@MatteoItalia Ugh. Nhiều ABI là một snafu, một phương pháp chữa trị cho một điều tồi tệ hơn căn bệnh này. Một số ARM hoàn toàn không có thanh ghi VFP hoặc NEON, một số có 16, 32. Trên Cortex-A8 và trước đó, công cụ NEON chạy một tá CC phía sau phần còn lại của lõi, do đó, việc chuyển một đầu ra vector sang GPR tốn kém nhiều. ARM đã làm tròn để làm điều đúng đắn - bắt buộc một tập hợp lớn các tính năng phổ biến.
Idonotexist Idillotexist

7

Bạn luôn cần phải nhắm mục tiêu một nền tảng. Trong trường hợp đơn giản nhất, CPU mục tiêu trực tiếp chạy mã được biên dịch trong tệp nhị phân (điều này gần tương ứng với các tệp thực thi COM của MS DOS). Hãy xem xét hai nền tảng khác nhau mà tôi vừa phát minh - Armistice và Intellio. Trong cả hai trường hợp, chúng tôi sẽ có một chương trình hello world đơn giản xuất ra 42 trên màn hình. Tôi cũng sẽ cho rằng bạn đang sử dụng ngôn ngữ đa nền tảng theo cách không biết nền tảng, vì vậy mã nguồn giống nhau cho cả hai:

Print(42)

Trên Armistice, bạn có một trình điều khiển thiết bị đơn giản, đảm nhiệm việc in số, vì vậy tất cả những gì bạn phải làm là xuất ra một cổng. Trong ngôn ngữ lắp ráp di động của chúng tôi, điều này sẽ tương ứng với một cái gì đó như thế này:

out 1234h, 42

Tuy nhiên, hoặc hệ thống Intellio không có điều đó, vì vậy nó phải trải qua các lớp khác:

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

Rất tiếc, chúng tôi đã có một sự khác biệt lớn giữa hai người, trước khi chúng tôi thậm chí nhận được mã máy! Điều này gần tương ứng với loại khác biệt mà bạn có giữa Linux và MS DOS, hoặc PC của IBM và X-Box (mặc dù cả hai có thể sử dụng cùng một CPU).

Nhưng đó là những gì hệ điều hành dành cho. Giả sử chúng ta có một HAL đảm bảo rằng tất cả các cấu hình phần cứng khác nhau được xử lý theo cùng một cách trên lớp ứng dụng - về cơ bản, chúng ta sẽ sử dụng phương pháp Intellio ngay cả trên Armistice và mã "lắp ráp di động" của chúng ta kết thúc giống nhau. Điều này được sử dụng bởi cả các hệ thống giống như Unix và Windows hiện đại, thường là ngay cả trong các kịch bản nhúng. Tốt - bây giờ chúng ta có thể có cùng mã lắp ráp di động trên cả Armistice và Intellio. Nhưng những gì về nhị phân?

Như chúng ta đã giả định, CPU cần thực thi nhị phân trực tiếp. Hãy xem dòng đầu tiên của mã của chúng tôi mov a, 10h, trên Intellio:

20 10

Oh. Hóa ra mov a, constantlà phổ biến đến mức nó có hướng dẫn riêng, với opcode riêng. Armistice xử lý việc này như thế nào?

36 01 00 10

Hừm. Có opcode cho mov.reg.imm, vì vậy chúng tôi cần một đối số khác để chọn đăng ký mà chúng tôi đang gán. Và hằng số luôn là một từ 2 byte, theo ký hiệu cuối lớn - đó chỉ là cách Armistice được thiết kế, trên thực tế, tất cả các hướng dẫn trong Armistice đều dài 4 byte, không có ngoại lệ.

Bây giờ hãy tưởng tượng chạy nhị phân từ Intellio trên Armistice: CPU bắt đầu giải mã hướng dẫn, tìm opcode 20h. Trên Armistice, điều này tương ứng, nói, với and.imm.reghướng dẫn. Nó cố gắng đọc hằng số từ 2 byte (đã đọc 10XX, đã có vấn đề) và sau đó là số đăng ký (khác XX). Chúng tôi đang thực hiện hướng dẫn sai, với các đối số sai. Và tệ hơn nữa, hướng dẫn tiếp theo sẽ hoàn toàn không có thật, bởi vì chúng tôi thực sự đã ăn một hướng dẫn khác, nghĩ rằng đó là dữ liệu.

Ứng dụng này không có cơ hội hoạt động và rất có thể nó sẽ bị sập hoặc treo gần như ngay lập tức.

Bây giờ, điều này không có nghĩa là một thực thi luôn cần phải nói nó chạy trên Intellio hoặc Armistice. Bạn chỉ cần xác định một nền tảng độc lập với CPU (như bashtrên Unix) hoặc cả CPU và HĐH (như Java hoặc .NET, và hiện tại thậm chí là JavaScript, loại). Trong trường hợp này, ứng dụng có thể sử dụng một tệp thực thi cho tất cả các CPU và HĐH khác nhau, trong khi có một số ứng dụng hoặc dịch vụ trên hệ thống đích (nhắm trực tiếp vào CPU và / hoặc HĐH chính xác) để dịch mã độc lập với nền tảng thành thứ gì đó CPU thực sự có thể thực thi. Điều này có thể hoặc không đi kèm với hiệu quả, chi phí hoặc khả năng.

CPU thường đến trong các gia đình. Ví dụ: tất cả các CPU từ họ x86 đều có một bộ hướng dẫn chung được mã hóa theo cùng một cách chính xác, vì vậy mọi CPU x86 có thể chạy mọi chương trình x86, miễn là nó không cố gắng sử dụng bất kỳ tiện ích mở rộng nào (ví dụ: hoạt động điểm nổi hoặc hoạt động vector). Trên x86, các ví dụ phổ biến nhất hiện nay là Intel và AMD. Atmel là một công ty nổi tiếng thiết kế CPU trong gia đình ARM, khá phổ biến cho các thiết bị nhúng. Apple cũng có CPU ARM của riêng họ, ví dụ.

Nhưng ARM hoàn toàn không tương thích với x86 - chúng có các yêu cầu thiết kế rất khác nhau và có rất ít điểm chung. Các hướng dẫn có opcodes hoàn toàn khác nhau, chúng được giải mã theo một cách khác, các địa chỉ bộ nhớ được xử lý khác nhau ... Có thể tạo một nhị phân chạy trên cả CPU x86 và CPU ARM, bằng cách sử dụng một số thao tác an toàn để phân biệt giữa hai và nhảy đến hai bộ hướng dẫn hoàn toàn khác nhau, nhưng điều đó vẫn có nghĩa là bạn có các hướng dẫn riêng cho cả hai phiên bản, chỉ với một bootstrapper chọn bộ chính xác khi chạy.


3

Có thể đặt lại câu hỏi này vào một môi trường có thể quen thuộc hơn. Bằng cách tương tự:

"Tôi có một chương trình Ruby mà tôi muốn chạy, nhưng nền tảng của tôi chỉ có trình thông dịch Python. Tôi có thể sử dụng trình thông dịch Python để chạy chương trình Ruby của tôi không, hoặc tôi có phải viết lại chương trình của mình bằng Python không?"

Kiến trúc tập lệnh ("đích") là một ngôn ngữ - "ngôn ngữ máy" - và các CPU khác nhau thực hiện các ngôn ngữ khác nhau. Vì vậy, yêu cầu CPU ARM chạy nhị phân Intel rất giống như cố gắng chạy chương trình Ruby bằng trình thông dịch Python.


2

gcc sử dụng thuật ngữ '' architecture '' để có nghĩa là '' tập lệnh '' của một CPU cụ thể và "đích" bao gồm sự kết hợp giữa CPU và kiến ​​trúc, cùng với các biến khác như ABI, libc, endian-ness và hơn thế nữa (có thể bao gồm cả "kim loại trần"). Một trình biên dịch điển hình có một tập hợp các kết hợp đích hạn chế (có thể là một ABI, một họ CPU, nhưng có thể cả 32 và 64 bit). Trình biên dịch chéo thường có nghĩa là trình biên dịch có mục tiêu khác với hệ thống mà nó chạy hoặc một trình biên dịch có nhiều mục tiêu hoặc ABI (xem thêm phần này ).

Các nhị phân có thể di động trên các kiến ​​trúc CPU khác nhau không?

Nói chung, không. Một nhị phân theo thuật ngữ thông thường là mã đối tượng riêng cho một họ CPU hoặc CPU cụ thể. Nhưng, có một số trường hợp chúng có thể có độ di động vừa phải:

  • một kiến ​​trúc là một siêu kiến ​​trúc của một kiến ​​trúc khác (thường là các nhị phân x86 nhắm vào i386 hoặc i686 chứ không phải là x86 mới nhất và lớn nhất, vd -march=core2)
  • một kiến ​​trúc cung cấp mô phỏng gốc hoặc bản dịch của một kiến ​​trúc khác (bạn có thể đã nghe nói về Crusoe ) hoặc cung cấp các bộ đồng xử lý tương thích (ví dụ: PS2 )
  • Hệ điều hành và thời gian chạy hỗ trợ multiarch (ví dụ: khả năng chạy nhị phân x86 32 bit trên x86_64) hoặc làm cho VM / JIT liền mạch (Android sử dụng Dalvik hoặc ART )
  • có hỗ trợ cho các tệp nhị phân "béo" về cơ bản chứa mã trùng lặp cho mỗi kiến ​​trúc được hỗ trợ

Nếu bạn bằng cách nào đó quản lý để giải quyết vấn đề này, thì vấn đề nhị phân di động khác của vô số phiên bản thư viện (glibc tôi đang nhìn bạn) sẽ xuất hiện. (Hầu hết các hệ thống nhúng giúp bạn tiết kiệm ít nhất từ ​​vấn đề cụ thể đó.)

Nếu bạn chưa có, bây giờ là thời điểm tốt để chạy gcc -dumpspecsgcc --target-helpđể xem bạn đang chống lại điều gì.

Các nhị phân chất béo có nhiều nhược điểm khác nhau , nhưng vẫn có những ứng dụng tiềm năng ( EFI ).

Tuy nhiên, có hai sự cân nhắc khác bị thiếu trong các câu trả lời khác: ELF và trình thông dịch ELF và hỗ trợ nhân Linux cho các định dạng nhị phân tùy ý . Tôi sẽ không đi vào chi tiết về các nhị phân hoặc mã byte cho các bộ xử lý không có thực ở đây, mặc dù có thể coi chúng là "bản địa" và thực thi Java hoặc các mã nhị phân Python được biên dịch , các nhị phân như vậy độc lập với kiến ​​trúc phần cứng (nhưng thay vào đó phụ thuộc trên phiên bản VM có liên quan, cuối cùng chạy nhị phân gốc).

Bất kỳ hệ thống Linux hiện đại nào cũng sẽ sử dụng nhị phân ELF (chi tiết kỹ thuật trong tệp PDF này ), trong trường hợp nhị phân ELF động, hạt nhân chịu trách nhiệm tải hình ảnh vào bộ nhớ nhưng đó là công việc của 'trình thông dịch' được đặt trong ELF tiêu đề để làm việc nặng. Thông thường, điều này liên quan đến việc đảm bảo tất cả các thư viện động phụ thuộc đều có sẵn (với sự trợ giúp của phần '' Động 'liệt kê các thư viện và một số cấu trúc khác liệt kê các ký hiệu được yêu cầu) - nhưng đây gần như là một lớp hướng dẫn mục đích chung.

$ 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.2cũng là nhị phân ELF, nó không có trình thông dịch và là mã nhị phân riêng.)

Vấn đề với ELF là tiêu đề trong tệp nhị phân ( readelf -h /bin/ls) đánh dấu nó cho một kiến ​​trúc cụ thể, lớp (32 hoặc 64 bit), endian-ness và ABI (nhị phân chất béo "phổ quát" của Apple sử dụng định dạng nhị phân thay thế Mach-O thay vào đó giải quyết vấn đề này, điều này bắt nguồn từ NextSTEP). Điều này có nghĩa là một thực thi ELF phải phù hợp với hệ thống mà nó sẽ được chạy trên đó. Một lối thoát là trình thông dịch, đây có thể là bất kỳ tệp thực thi nào (bao gồm một trích xuất hoặc ánh xạ các phần phụ cụ thể của kiến ​​trúc nhị phân ban đầu và gọi chúng), nhưng bạn vẫn bị hạn chế bởi loại ELF mà hệ thống của bạn sẽ cho phép chạy . (FreeBSD có một cách thú vị để xử lý các tệp ELF của Linux , nó brandelfsửa đổi trường ELF ABI.)

Có (sử dụng binfmt_misc) hỗ trợ Mach-O trên linux , có một ví dụ ở đó chỉ cho bạn cách tạo và chạy tệp nhị phân (32- & 64-bit). Tài nguyên forks / ADS , như được thực hiện ban đầu trên Mac, có thể là một cách giải quyết, nhưng không có hệ thống tệp Linux gốc nào hỗ trợ điều này.

Ít nhiều điều tương tự áp dụng cho các mô-đun hạt nhân, .kocác tệp cũng là ELF (mặc dù chúng không có bộ thông dịch). Trong trường hợp này, có một lớp bổ sung sử dụng phiên bản kernel ( uname -r) trong đường dẫn tìm kiếm, về mặt lý thuyết có thể được thực hiện thay thế trong ELF với phiên bản, nhưng ở một mức độ phức tạp và ít đạt được tôi nghi ngờ.

Như đã lưu ý ở nơi khác, Linux không hỗ trợ nhị phân chất béo, nhưng có một dự án nhị phân chất béo đang hoạt động: FatELF . Nó đã tồn tại trong nhiều năm , nó không bao giờ được tích hợp vào hạt nhân tiêu chuẩn một phần do những lo ngại về bằng sáng chế (hiện đã hết hạn). Tại thời điểm này, nó đòi hỏi cả hỗ trợ kernel và toolchain. Nó không sử dụng binfmt_misccách tiếp cận, điều này phụ bước các vấn đề tiêu đề ELF và cũng cho phép các mô-đun hạt nhân béo.

  1. Nếu tôi có một ứng dụng được biên dịch để chạy trên 'x86 đích, phiên bản hệ điều hành linux xyz', tôi có thể chạy cùng một nhị phân được biên dịch trên hệ thống khác 'ARM đích, phiên bản hệ điều hành linux xyz' không?

Không phải với ELF, nó sẽ không cho phép bạn làm điều này.

  1. Nếu ở trên là không đúng, cách duy nhất là lấy mã nguồn ứng dụng để xây dựng lại / biên dịch lại bằng cách sử dụng chuỗi công cụ có liên quan 'ví dụ: arm-linux-gnueabi'?

Câu trả lời đơn giản là đồng ý. (Các câu trả lời phức tạp bao gồm mô phỏng, biểu diễn trung gian, người dịch và JIT; ngoại trừ trường hợp "hạ cấp" một nhị phân i686 để chỉ sử dụng các mã i386 có thể không thú vị ở đây và việc sửa lỗi ABI có thể khó như dịch mã gốc. )

  1. Tương tự, nếu tôi có một mô-đun hạt nhân có thể tải (trình điều khiển thiết bị) hoạt động trên 'mục tiêu x86, phiên bản hệ điều hành linux xyz', tôi có thể chỉ tải / sử dụng cùng một .ko trên hệ thống khác 'Mục tiêu ARM, phiên bản hệ điều hành linux xyz' ?

Không, ELF sẽ không cho phép bạn làm điều này.

  1. Nếu ở trên là không đúng, cách duy nhất là lấy mã nguồn trình điều khiển để xây dựng lại / biên dịch lại bằng cách sử dụng chuỗi công cụ có liên quan ', ví dụ: arm-linux-gnueabi'?

Câu trả lời đơn giản là đồng ý. Tôi tin rằng FatELF cho phép bạn xây dựng một .kokiến trúc đa kiến ​​trúc, nhưng tại một số điểm, một phiên bản nhị phân cho mọi kiến ​​trúc được hỗ trợ phải được tạo. Những thứ yêu cầu mô-đun hạt nhân thường đi kèm với nguồn và được xây dựng theo yêu cầu, ví dụ VirtualBox thực hiện điều này.

Đây đã là một câu trả lời lan man dài, chỉ còn một đường vòng nữa. Hạt nhân đãsẵn một máy ảo, mặc dù là máy chuyên dụng: máy ảo BPF được sử dụng để khớp với các gói. Bộ lọc có thể đọc được của con người "host foo chứ không phải port 22") được biên dịch thành mã byte và bộ lọc gói nhân thực thi nó . EBPF mới không chỉ dành cho các gói, theo lý thuyết là mã VM có thể di động trên bất kỳ linux hiện đại nào và sẽ hỗ trợ nó nhưng vì lý do bảo mật, nó có thể sẽ không phù hợp với bất kỳ điều gì ngoài quy tắc quản trị.


Bây giờ, tùy thuộc vào mức độ hào phóng của bạn với định nghĩa của tệp thực thi nhị phân, bạn có thể (ab) sử dụng binfmt_miscđể triển khai hỗ trợ nhị phân chất béo với tập lệnh shell và tệp ZIP dưới dạng định dạng chứa:

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

Gọi đây là "wozbin" và thiết lập nó với một cái gì đó như:

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

Điều này đăng ký .wozcác tệp với kernel, wozbintập lệnh được gọi thay vào đó với đối số đầu tiên được đặt thành đường dẫn của .woztệp được gọi .

Để có được một .woz tệp di động (chất béo) , chỉ cần tạo một test.woztệp ZIP với phân cấp thư mục để:

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

Trong mỗi thư mục arch / OS / libc (một lựa chọn tùy ý) đặt testnhị phân và các thành phần dành riêng cho kiến ​​trúc như .socác tệp. Khi bạn gọi nó, thư mục con cần thiết được trích xuất vào hệ thống tập tin trong bộ nhớ tmpfs ( /mnt/tmpfsở đây) và được gọi.


0

berry boot, giải quyết một số vấn đề của bạn .. nhưng nó không khắc phục được vấn đề làm thế nào để chạy trên bản phân phối linux hf, Normall / regullAr cho x86-32 / 64bit.

Tôi nghĩ rằng nó nên được xây dựng trong isolinux (Boatloader linux trên usb) một số trình chuyển đổi trực tiếp những gì có thể nhận ra bản phân phối regullar và trong chuyến đi / chuyển đổi trực tiếp sang hf.

Tại sao? Bởi vì nếu mỗi linux có thể được chuyển đổi bằng berry boot sang hoạt động trên arm-hf để nó có thể xây dựng cơ chế khởi động bery thành isolinux, chúng ta khởi động bằng cách sử dụng exaple Eacher hoặc được xây dựng trong đĩa khởi động ub Ubuntu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.