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 และอนุญาตให้โมดูลเคอร์เนลไขมันเกินไป
- หากฉันมีแอพพลิเคชั่นที่คอมไพล์ให้ทำงานบน 'x86 target, linux OS version xyz', ฉันจะสามารถรันไบนารีที่คอมไพล์เดียวกันบนระบบอื่น 'เป้าหมาย ARM, linux OS เวอร์ชัน xyz' ได้หรือไม่?
ไม่ใช่กับเอลฟ์มันจะไม่ยอมให้คุณทำเช่นนี้
- หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการรับซอร์สโค้ดของแอปพลิเคชันเพื่อสร้าง / คอมไพล์ซ้ำโดยใช้ toolchain ที่เกี่ยวข้อง 'ตัวอย่างเช่น arm-linux-gnueabi'
คำตอบง่ายๆคือใช่ (คำตอบที่ซับซ้อนรวมถึงการเลียนแบบการเป็นตัวแทนระดับกลางนักแปลและ JIT ยกเว้นกรณีของ "การลดระดับ" ไบนารี i686 เพื่อใช้เฉพาะ opcodes i386 เท่านั้นพวกเขาอาจไม่น่าสนใจที่นี่และการแก้ไข ABI นั้นอาจเป็นเรื่องยาก )
- ในทำนองเดียวกันถ้าฉันมีโมดูลเคอร์เนลที่สามารถโหลดได้ (ไดรเวอร์อุปกรณ์) ที่ทำงานบน 'x86 เป้าหมาย, linux OS เวอร์ชัน xyz' ฉันสามารถโหลด / ใช้. ko เดียวกันที่คอมไพล์ได้ในระบบ 'เป้าหมาย ARM, linux OS เวอร์ชัน xyz' ?
ไม่เอลฟ์จะไม่ยอมให้คุณทำเช่นนี้
- หากข้างต้นไม่เป็นความจริงวิธีเดียวคือการได้รับซอร์สโค้ดไดรเวอร์เพื่อสร้าง / คอมไพล์ใหม่โดยใช้ 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
นี่) และเรียกใช้