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 -dumpspecs
và gcc --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.2
cũ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ó brandelf
sử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, .ko
cá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_misc
cá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.
- 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.
- 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. )
- 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.
- 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 .ko
kiế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 đã có 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ý .woz
các tệp với kernel, wozbin
tậ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 .woz
tệ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.woz
tệ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 test
nhị phân và các thành phần dành riêng cho kiến trúc như .so
cá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.