Linux ที่สามารถเรียกใช้งานได้จะถูกคอมไพล์ใน "รสชาติ" ของ Linux หรือไม่


59

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

สถาปัตยกรรมของเครื่องจักรมีความสำคัญในกรณีเช่นนี้หรือไม่?

int main()
{
  return (99);
}

2
ขอบคุณทุกคนสำหรับคำตอบที่โดดเด่น! ฉันเรียนรู้มากกว่าที่ฉันคาดไว้ ฉันทำโค้ดอย่างง่าย ๆ ตามจุดประสงค์เพื่อให้มันขึ้นอยู่กับห้องสมุดน้อยที่สุด แต่ฉันควรจะพูดอย่างนั้นจริงๆ การเข้ารหัส C ++ ของฉันส่วนใหญ่ข้ามแพลตฟอร์มที่เกี่ยวข้องกับการพัฒนาด้วยเครื่องมือ Microsoft เช่น Visual Studio จากนั้นจึงย้ายรหัสไปยังระบบ * nix และทำการคอมไพล์ใหม่
JCDeen

4
หลายแง่มุมและการพิจารณาที่แสดงที่นี่ทำให้ฉันประหลาดใจ! ฉันหวังว่าฉันจะเลือกได้หลายคำตอบ ขอขอบคุณอีกครั้งสำหรับทุกคน! อย่างจริงใจ
JCDeen

2
Android ยังเป็นระบบปฏิบัติการบน Linux ขอให้โชคดีที่ใช้โค้ดใด ๆ ที่คอมไพล์glibcแล้วหรือกลับกัน จริงอยู่ที่มันเป็นไปไม่ได้เลย
undercat

2
เพื่อความเข้ากันได้สูงสุดของเครื่องมือบรรทัดคำสั่งคุณอาจต้องการใช้ uClibc, musl หรือ dietlibc แทน glibc และเชื่อมโยงไฟล์ปฏิบัติการแบบ 32 บิตของคุณแบบคงที่ ( gcc -m32 -static) ด้วยการทำเช่นนั้น i386 หรือ amd64 Linux ใด ๆ จะสามารถเรียกใช้ปฏิบัติการได้
pts

10
คุณควรจะกลับมา42 ! :)
Homunculus Reticulli

คำตอบ:


49

มันขึ้นอยู่กับ. บางสิ่งที่รวบรวมไว้สำหรับ IA-32 (Intel 32 บิต) อาจทำงานบน amd64 เนื่องจาก Linux บน Intel ยังคงใช้งานร่วมกับแอพพลิเคชั่นแบบ 32 บิตได้ (ด้วยการติดตั้งซอฟต์แวร์ที่เหมาะสม) นี่คือcodeคอมไพล์ของคุณใน RedHat 7.3 ระบบ 32 บิต (ประมาณ 2002, gcc เวอร์ชั่น 2.96) จากนั้นไบนารีจะถูกคัดลอกไปยังและทำงานบนระบบ Centos 7.4 64- บิต (ประมาณปี 2560):

-bash-4.2$ file code
code: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, not stripped
-bash-4.2$ ./code
-bash: ./code: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
-bash-4.2$ sudo yum -y install glibc.i686
...
-bash-4.2$ ./code ; echo $?
99

Ancient RedHat 7.3 ถึง Centos 7.4 (โดยหลักแล้ว RedHat Enterprise Linux 7.4) ยังคงอยู่ในตระกูล "การกระจาย" เดียวกันดังนั้นจึงน่าจะมีความสะดวกในการพกพาดีกว่าการติดตั้ง "Linux จากศูนย์" แบบสุ่มบางส่วนในปี 2002 .

สิ่งที่รวบรวมสำหรับ amd64 จะไม่ทำงานบน Linux รุ่น 32 บิตเท่านั้น (ฮาร์ดแวร์เก่าไม่ทราบเกี่ยวกับฮาร์ดแวร์ใหม่) นี่เป็นความจริงสำหรับซอฟต์แวร์ใหม่ที่รวบรวมในระบบที่ทันสมัยที่มีวัตถุประสงค์เพื่อใช้งานกับสิ่งเก่าโบราณเช่นห้องสมุดและแม้กระทั่งการเรียกใช้ระบบอาจไม่สามารถย้อนกลับได้แบบพกพาดังนั้นอาจต้องใช้เทคนิคการรวบรวมหรือรับคอมไพเลอร์เก่าและอื่น ๆ รวบรวมในระบบเก่า (นี่เป็นเหตุผลที่ดีในการเก็บเครื่องเสมือนของโบราณไว้รอบตัว)

สถาปัตยกรรมไม่สำคัญ amd64 (หรือ IA-32) นั้นแตกต่างอย่างมากจาก ARM หรือ MIPS ดังนั้นไบนารีจากหนึ่งในนั้นจะไม่ถูกคาดหวังให้ทำงานบนอีก ในระดับการประกอบmainส่วนของรหัสของคุณใน IA-32 คอมไพล์ผ่านgcc -S code.cเพื่อ

main:
    pushl %ebp
    movl %esp,%ebp
    movl $99,%eax
    popl %ebp
    ret

ซึ่งระบบ amd64 สามารถจัดการกับ (บนระบบ Linux - OpenBSD โดยตรงกันข้ามกับ amd64 ไม่รองรับไบนารี 32 บิตการทำงานร่วมกันย้อนหลังกับ archs เก่าจะให้ห้องผู้บุกรุกเช่นCVE-2014-8866และเพื่อน ๆ ) ในขณะเดียวกันในระบบ MIPS ขนาดใหญ่ mainแทนการรวบรวมเพื่อ:

main:
        .frame  $fp,8,$31
        .mask   0x40000000,-4
        .fmask  0x00000000,0
        .set    noreorder
        .set    nomacro
        addiu   $sp,$sp,-8
        sw      $fp,4($sp)
        move    $fp,$sp
        li      $2,99
        move    $sp,$fp
        lw      $fp,4($sp)
        addiu   $sp,$sp,8
        j       $31
        nop

ซึ่งโปรเซสเซอร์ Intel จะไม่ทราบว่าจะทำอย่างไรและเช่นเดียวกันสำหรับการประกอบ Intel ใน MIPS

คุณอาจใช้ QEMU หรือโปรแกรมจำลองอื่น ๆ เพื่อเรียกใช้โค้ดต่างประเทศ (อาจช้ามาก)

แต่! รหัสของคุณเป็นรหัสที่ง่ายมากดังนั้นจะมีปัญหาเรื่องการพกพาน้อยกว่าสิ่งอื่นใด โปรแกรมมักจะใช้ประโยชน์จากห้องสมุดที่มีการเปลี่ยนแปลงตลอดเวลา (glibc, openssl, ... ); สำหรับคนเหล่านั้นอาจจำเป็นต้องติดตั้งไลบรารี่ต่าง ๆ ที่เก่ากว่า (เช่น RedHat มักจะใส่ "compat" ไว้ในชื่อแพ็กเกจเช่น)

compat-glibc.x86_64                     1:2.12-4.el7.centos

หรืออาจกังวลเกี่ยวกับการเปลี่ยนแปลง ABI (Application Binary Interface) สำหรับวิธีเก่า ๆ ที่ใช้ glibc หรือเปลี่ยนแปลงเร็ว ๆ นี้เนื่องจาก C ++ 11 หรือ C ++ รุ่นอื่น ๆ เราสามารถคอมไพล์แบบสแตติก (เพิ่มขนาดไบนารีบนดิสก์) เพื่อพยายามหลีกเลี่ยงปัญหาในไลบรารีแม้ว่าจะมีบางไบนารีแบบเก่าก็ตามหรือไม่ขึ้นอยู่กับว่าการกระจาย Linux แบบเก่านั้นรวบรวมทุกอย่างแบบไดนามิก (RedHat: ใช่) หรือไม่ ในทางตรงกันข้ามสิ่งต่าง ๆ เช่นpatchelfสามารถ rejigger dynamic (ELF แต่อาจไม่ใช่a.outรูปแบบ) เพื่อใช้ไลบรารีอื่น

แต่! ความสามารถในการเรียกใช้โปรแกรมเป็นสิ่งหนึ่งและจริง ๆ แล้วทำสิ่งที่มีประโยชน์กับโปรแกรมอื่น ไบนารีของ Intel เก่า 32 บิตอาจมีปัญหาด้านความปลอดภัยหากพวกเขาขึ้นอยู่กับรุ่นของ OpenSSL ที่มีปัญหาด้านความปลอดภัยที่น่ากลัวและไม่ได้ backported อยู่ในนั้นหรือโปรแกรมอาจไม่สามารถเจรจาต่อรองกับเว็บเซิร์ฟเวอร์ที่ทันสมัยได้ เซิร์ฟเวอร์ปฏิเสธโปรโตคอลและยันต์เก่าของโปรแกรมเก่า) หรือโปรโตคอล SSH เวอร์ชัน 1 ไม่ได้รับการสนับสนุนอีกต่อไปหรือ ...


14
ย่อหน้าแรก: ไม่ Intel เรียกมันว่า "Intel 64" (วันนี้หลังจากผ่านชื่ออื่นก่อนหน้านี้) IA-64 หมายถึง Itanium ไม่ใช่สิ่งใดที่เข้ากันได้กับ x86
ฮอบส์

1
@ ฮอบส์ขอบคุณคุณฉันได้แทนที่การอ้างอิงเหล่านั้นด้วย amd64; ฉันจะตั้งชื่อให้ฝ่ายการตลาดของ Intel
thrig

3
ทำไมไม่พูดถึงการเชื่อมโยงแบบคงที่?
dcorking

2
มันไม่ใช่แค่ไลบรารี ABIs ที่เปลี่ยนแปลง - ส่วนต่อประสาน syscall ของเคอร์เนลก็ขยายออกไปตามเวลาเช่นกัน หมายเหตุfor GNU/Linux 2.6.32(หรือดังกล่าว) file /usr/bin/lsในการส่งออกของ
Charles Duffy

1
@Wilbert คุณอาจจะขาดหายไปว่า thrig นั้นอ้างถึงRed Hat Linuxที่แตกต่างจาก Red Hat Enterprise Linux
บ๊อบ

68

ในระยะสั้น: ถ้าคุณกำลังการไบนารีรวบรวมจากพื้นที่หนึ่งไปยังอีกที่ใช้เหมือนกัน (หรือเข้ากันได้) สถาปัตยกรรมคุณอาจจะสมบูรณ์ดีพามันไปยังอีกกระจาย อย่างไรก็ตามเมื่อความซับซ้อนของรหัสเพิ่มขึ้นโอกาสที่จะถูกเชื่อมโยงกับไลบรารีที่ไม่ได้ติดตั้ง ติดตั้งในตำแหน่งอื่น หรือติดตั้งในเวอร์ชันอื่นเพิ่มขึ้น ทำตัวอย่างรหัสของคุณซึ่งlddรายงานการพึ่งพาต่อไปนี้เมื่อรวบรวมกับgcc -o exit-test exit-test.cโฮสต์ Ubuntu Linux (มาจาก Debian):

$ ldd exit-test
    linux-gate.so.1 =>  (0xb7748000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb757b000)
    /lib/ld-linux.so.2 (0x8005a000)

เห็นได้ชัดว่าไบนารีนี้จะไม่ทำงานถ้าฉันเตะมันเพื่อพูดว่า Mac ( ./exit-test: cannot execute binary file: Exec format error) ลองย้ายไปที่กล่อง RHEL:

$ ./exit-test
-bash: ./exit-test: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory

โอ้ที่รัก เหตุใดจึงเป็นเช่นนี้

$ ls /lib/ld-l* # reference the `ldd` output above
ls: cannot access /lib/ld-l*: No such file or directory

แม้สำหรับกรณีการใช้งานนี้การยกมันล้มเหลวเนื่องจากไม่มีไลบรารีที่แชร์

อย่างไรก็ตามหากฉันรวบรวมมันด้วยการgcc -static exit-test-static exit-test.cย้ายพอร์ตไปยังระบบที่ไม่มีไลบรารีทำงานได้ดี แน่นอนค่าใช้จ่ายของพื้นที่ดิสก์:

$ ls -l ./exit-test{,-static}
-rwxr-xr-x  1 username  groupname    7312 Jan 29 14:18 ./exit-test
-rwxr-xr-x  1 username  groupname  728228 Jan 29 14:27 ./exit-test-static

โซลูชันที่ทำงานได้อีกอย่างหนึ่งคือการติดตั้งไลบรารีที่จำเป็นบนโฮสต์ใหม่

เช่นเดียวกับหลายสิ่งในจักรวาล U&L นี่คือแมวที่มีสกินจำนวนมากซึ่งมีสองอย่างที่อธิบายไว้ด้านบน


4
แน่นอนฉันลืมเกี่ยวกับไบนารีคงที่ ผู้ค้าบางรายใช้ไบนารีแบบคงที่และผู้เขียนมัลแวร์บางคนก็เช่นกันเพื่อเพิ่มความเข้ากันได้ของไบนารีระหว่างสถาปัตยกรรม
Rui F Ribeiro

8
Forklifting ... ?
253751

2
@immibis ฉันคิดว่ามันหมายถึงการคัดลอกข้อมูล (ปฏิบัติการ) จากสภาพแวดล้อมหนึ่ง (distro) ไปยังอีกที่ซึ่งข้อมูลไม่ได้ออกแบบมาสำหรับสภาพแวดล้อมปลายทาง
wjandrea

13
ตัวอย่างลีนุกซ์ของคุณนั้นค่อนข้างน่าเสียดายและแสดงให้เห็นถึงจุดของคุณเกี่ยวกับสถาปัตยกรรมมากกว่าการกระจาย: คุณสร้างไบนารี่ 32 บิตบนเดเบียนและพยายามเรียกใช้มันบน 64-RHEL; สิ่งเหล่านั้นคือสถาปัตยกรรมที่แตกต่างกัน ... ไบนารีสถาปัตยกรรมเดียวกันที่มีการพึ่งพาไลบรารีเพียงเล็กน้อยจึงสามารถคัดลอกได้ดี
สตีเฟ่น Kitt

7
@Malters ฉันไม่ได้บอกว่ามันไม่มีเหตุผลฉันกำลังบอกว่ามันเป็นตัวอย่างที่ไม่ดีเมื่อ DopeGhoti กำลังพยายามทำ (คุณไม่สามารถคัดลอกไบนารีจากการกระจายหนึ่งไปยังอีกที่หนึ่ง - ซึ่งเป็นสิ่งที่ผิด) แน่นอนว่า Linux 64 บิตบน Intel รองรับการใช้งานโปรแกรมเรียกทำงานแบบ 32 บิตได้เช่นกันพร้อมกับโครงสร้างพื้นฐานที่เหมาะสม ตัวอย่างที่ถูกต้องในกรณีนี้ IMO จะสร้างamd64ไบนารีและเรียกใช้บนamd64การกระจายอื่นหรือสร้างi386ไบนารีและเรียกใช้บนi386การกระจายอื่น
สตีเฟ่น Kitt

25

การเพิ่มคำตอบ @thrig และ @DopeGhoti ที่ยอดเยี่ยม: ระบบปฏิบัติการ Unix หรือ Unix เช่น Unix รวมถึง Linux ได้รับการออกแบบและจัดวางแบบดั้งเดิมเพื่อความสะดวกในการพกพาซอร์สโค้ดมากกว่าไบนารี

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

หากทำการย้ายโค้ดขั้นสูงเพิ่มเติมจาก Linux เวอร์ชันเก่าในเวลาที่กำหนดหรือโปรแกรมที่เฉพาะเจาะจงมากขึ้นเช่นโมดูลเคอร์เนลสำหรับเคอร์เนลเวอร์ชันต่าง ๆ คุณอาจต้องปรับเปลี่ยนและแก้ไขซอร์สโค้ดเป็นบัญชีสำหรับไลบรารี / APIs / ABIs ที่คัดค้าน


19

ตามค่าเริ่มต้นคุณจะพบปัญหาเกี่ยวกับไลบรารีภายนอก คำตอบอื่น ๆ บางส่วนไปที่รายละเอียดเพิ่มเติมเกี่ยวกับปัญหาเหล่านั้นดังนั้นฉันจะไม่ทำซ้ำงานของพวกเขา

อย่างไรก็ตามคุณสามารถคอมไพล์โปรแกรมจำนวนมากได้แม้กระทั่งโปรแกรมที่ไม่น่าสนใจเพื่อพกพาระหว่างระบบ Linux ที่สำคัญคือเครื่องมือที่เรียกว่าลินุกซ์ฐานมาตรฐาน LSBถูกออกแบบมาสำหรับการสร้างเพียงแค่เหล่านี้ประเภทของการใช้งานแบบพกพา คอมไพล์แอปพลิเคชันสำหรับ LSB v5.0 และมันจะทำงานบนสภาพแวดล้อม Linux อื่น ๆ (ของสถาปัตยกรรมเดียวกัน) ที่ใช้ LSB v5.0 Linux distros บางตัวเป็นไปตามมาตรฐาน LSB และอื่น ๆ รวมถึงชุดเครื่องมือ / ไลบรารี LSB เป็นแพ็คเกจที่ติดตั้งได้ หากคุณสร้างแอปพลิเคชันของคุณโดยใช้เครื่องมือ LSB (เช่นlsbccwrapper for gcc) และลิงก์ไปยังไลบรารี่รุ่น LSB คุณจะต้องสร้างแอปพลิเคชั่นแบบพกพา


และด้วยqemuคุณสามารถเรียกใช้โปรแกรมที่รวบรวมไว้สำหรับการวาดภาพที่แตกต่างกัน (ไม่ใช่ประสิทธิภาพสูง แต่คุณสามารถเรียกใช้งานได้)
Jasen

1
ฉันไม่ได้ตระหนักถึงชุดเครื่องมือฐานมาตรฐาน Linux ดังนั้นขอบคุณ! ฉันเริ่มทำงานกับ C / C ++ นานมากแล้วข้อมูลมากมายในคำตอบเหล่านี้เป็นสิ่งใหม่สำหรับฉัน และมีประโยชน์มาก
JCDeen

1
บทความ Wikipedia กล่าวว่า Debian และ Ubuntu ไม่ได้ติดตั้ง LSB (และไม่มีความตั้งใจที่จะทำเช่นนั้น)
BlackJack

2
@ BlackJack- ตัว distro ไม่ได้ใช้ 100% เป็นส่วนหนึ่งของ core OS แต่คุณสามารถติดตั้งไลบรารีและชุดเครื่องมือที่เข้ากันได้ของ LSB เป็นแพ็คเกจเสริม ฉันใช้ Ubuntu (ตัวอย่าง) เพื่อสร้างโปรแกรมที่เข้ากันได้กับ LSB ที่รันบน Suse และ Centos คุณแค่ต้องapt-get installใช้แพ็คเกจสองชุด
bta

10

อาจจะ.

สิ่งที่มีแนวโน้มที่จะทำลายมันรวมถึง

  1. สถาปัตยกรรมที่แตกต่าง เห็นได้ชัดว่าสถาปัตยกรรมที่แตกต่างกันโดยสิ้นเชิงจะไม่ทำงาน (ยกเว้นว่าคุณมีบางอย่างเช่นโหมดผู้ใช้ qemu ด้วย binfmt_misc แต่นั่นเป็นการตั้งค่าปกติแทบจะไม่) x86 ไบนารีอาจทำงานบน amd64 แต่เฉพาะในกรณีที่จำเป็นต้องมีไลบรารีแบบ 32 บิต
  2. เวอร์ชันห้องสมุด หาก soversion ไม่ถูกต้องจะไม่พบห้องสมุดเลย หาก soversion เหมือนกัน แต่ไบนารีนั้นสร้างขึ้นกับไลบรารีเวอร์ชันใหม่กว่าที่รันไว้มันอาจล้มเหลวในการโหลดเนื่องจากสัญลักษณ์ใหม่หรือสัญลักษณ์เวอร์ชันใหม่ โดยเฉพาะอย่างยิ่ง glibc เป็นผู้ใช้เวอร์ชันสัญลักษณ์อย่างมากดังนั้นไบนารีที่สร้างขึ้นกับ glibc ที่ใหม่กว่านั้นมีโอกาสมากที่จะล้มเหลวด้วย glibc รุ่นเก่า

หากคุณหลีกเลี่ยงการใช้ไลบรารีที่เปลี่ยนแปลงอย่างรวดเร็วให้หลีกเลี่ยงการเปลี่ยนแปลงสถาปัตยกรรมและสร้างบน distro ที่เก่าแก่ที่สุดที่คุณต้องการกำหนดเป้


4

นอกเหนือจากสิ่งที่กล่าวถึงก่อนหน้านี้มีการเปลี่ยนแปลงบางอย่างในรูปแบบไฟล์ที่ปฏิบัติการได้ ส่วนใหญ่ linux ใช้ ELF แต่รุ่นเก่าใช้ a.out หรือ COFF

จุดเริ่มต้นของ wikihole:

https://en.wikipedia.org/wiki/Comparison_of_executable_file_formats

อาจเป็นวิธีที่ทำให้รุ่นเก่าทำงานได้รูปแบบที่ใหม่กว่า แต่โดยส่วนตัวแล้วฉันไม่เคยดูเลย


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