application binary interface (ABI) คืออะไร?


493

ฉันไม่เคยเข้าใจชัดเจนว่า ABI คืออะไร โปรดอย่านำฉันไปที่บทความ Wikipedia ถ้าฉันเข้าใจได้ฉันจะไม่โพสต์ข้อความยาว ๆ ที่นี่

นี่คือความคิดของฉันเกี่ยวกับอินเทอร์เฟซต่าง ๆ :

รีโมตทีวีเป็นอินเทอร์เฟซระหว่างผู้ใช้กับทีวี เป็นนิติบุคคลที่มีอยู่ แต่ไร้ประโยชน์ (ไม่มีฟังก์ชั่นใด ๆ ) ด้วยตัวเอง ฟังก์ชั่นทั้งหมดสำหรับแต่ละปุ่มบนรีโมทนั้นมีการใช้งานในเครื่องรับโทรทัศน์

อินเทอร์เฟซ:เป็นเลเยอร์ "เอนทิตีที่มีอยู่" ระหว่าง functionalityและconsumerของฟังก์ชันการทำงานนั้น ส่วนต่อประสานไม่ได้ทำอะไรเลย มันแค่เรียกใช้ฟังก์ชั่นที่อยู่ข้างหลัง

ตอนนี้ขึ้นอยู่กับผู้ใช้ที่มีอินเทอร์เฟซชนิดต่าง ๆ

Command Line Interface (CLI)คำสั่งเป็นเอนทิตีที่มีอยู่ผู้บริโภคคือผู้ใช้และหน้าที่การใช้งานอยู่ด้านหลัง

functionality: ฟังก์ชั่นซอฟต์แวร์ของฉันที่แก้จุดประสงค์บางอย่างที่เราอธิบายอินเตอร์เฟซนี้

existing entities: คำสั่ง

consumer: ผู้ใช้งาน

หน้าต่างส่วนต่อประสานกราฟิกกับผู้ใช้ (GUI)ปุ่มและอื่น ๆ เป็นสิ่งที่มีอยู่และอีกครั้งที่ผู้บริโภคคือผู้ใช้

functionality: ฟังก์ชั่นซอฟต์แวร์ของฉันที่แก้ปัญหาที่เราอธิบายอินเตอร์เฟซนี้

existing entities: หน้าต่างปุ่ม ฯลฯ

consumer: ผู้ใช้งาน

แอปพลิเคชัน Application Interface Interface (API) (หรือให้ถูกต้องมากขึ้น) อินเทอร์เฟซ (ในการเขียนโปรแกรมแบบอินเทอร์แอคทีฟ) เป็นเอนทิตีที่มีอยู่ผู้บริโภคที่นี่คือโปรแกรมอื่นที่ไม่ใช่ผู้ใช้

functionality: ฟังก์ชั่นซอฟต์แวร์ของฉันที่แก้ปัญหาที่เราอธิบายอินเตอร์เฟซนี้

existing entities: ฟังก์ชั่นการเชื่อมต่อ (อาร์เรย์ของฟังก์ชั่น)

consumer: โปรแกรมอื่น / แอปพลิเคชัน

Application Binary Interface (ABI)นี่คือที่ที่ปัญหาของฉันเริ่มต้น

functionality: ???

existing entities: ???

consumer: ???

  • ฉันเขียนซอฟต์แวร์เป็นภาษาต่าง ๆ และมีอินเทอร์เฟซต่าง ๆ (CLI, GUI และ API) แต่ฉันไม่แน่ใจว่าฉันได้ให้ ABI ใด ๆ หรือไม่

Wikipedia พูดว่า:

ABIs ครอบคลุมรายละเอียดเช่น

  • ชนิดข้อมูลขนาดและการจัดตำแหน่ง
  • แบบแผนการเรียกซึ่งควบคุมวิธีการส่งผ่านข้อโต้แย้งของฟังก์ชันและการคืนค่า
  • หมายเลขการโทรของระบบและวิธีที่แอปพลิเคชันควรทำการโทรของระบบไปยังระบบปฏิบัติการ

ABIs อื่น ๆ สร้างรายละเอียดที่เป็นมาตรฐานเช่น

  • mangling ชื่อ C ++
  • การเผยแพร่ข้อยกเว้นและ
  • แผนการโทรระหว่างคอมไพเลอร์บนแพลตฟอร์มเดียวกัน แต่ไม่ต้องการความเข้ากันได้ข้ามแพลตฟอร์ม
  • ใครต้องการรายละเอียดเหล่านี้ กรุณาอย่าพูดระบบปฏิบัติการ ฉันรู้ว่าการเขียนโปรแกรมการชุมนุม ฉันรู้ว่าการเชื่อมโยงและการโหลดทำงานอย่างไร ฉันรู้ว่าสิ่งที่เกิดขึ้นภายใน

  • เหตุใดชื่อ C ++ จึงสร้างชื่อเข้ามา ฉันคิดว่าเรากำลังพูดถึงในระดับไบนารี ทำไมภาษามา?

อย่างไรก็ตามฉันได้ดาวน์โหลด[PDF] System V Application Binary Interface Edition 4.1 (1997-03-18)เพื่อดูว่ามันประกอบด้วยอะไรบ้าง ส่วนใหญ่มันไม่สมเหตุสมผลเลย

  • ทำไมมันมีสองบท (ที่ 4 และที่ 5) เพื่ออธิบายรูปแบบไฟล์เอลฟ์ ? ในความเป็นจริงเหล่านี้เป็นเพียงสองบทที่สำคัญของข้อกำหนดที่ บทที่เหลือเป็น "ตัวประมวลผลเฉพาะ" อย่างไรก็ตามฉันคิดว่ามันเป็นหัวข้อที่แตกต่างอย่างสิ้นเชิง โปรดอย่าพูดว่าข้อมูลจำเพาะรูปแบบไฟล์ของ ELF คือ ABI ไม่มีคุณสมบัติที่จะเป็นอินเทอร์เฟซตามข้อกำหนด

  • ฉันรู้ว่าเนื่องจากเรากำลังพูดคุยในระดับต่ำมันจะต้องเฉพาะเจาะจงมาก แต่ฉันไม่แน่ใจว่าเป็นเฉพาะ "ชุดคำสั่งสถาปัตยกรรม (ISA)" อย่างไร

  • ฉันจะหา ABI ของ Microsoft Windows ได้จากที่ใด

ดังนั้นนี่เป็นข้อความค้นหาที่สำคัญที่ทำให้ฉันรำคาญ


7
"กรุณาอย่าพูด OS" คอมไพเลอร์จำเป็นต้องรู้ ABI นักเชื่อมโยงจำเป็นต้องรู้ ABI เคอร์เนลจำเป็นต้องรู้ ABI เพื่อตั้งค่าโปรแกรมใน RAM เพื่อให้ทำงานได้อย่างถูกต้อง สำหรับ C ++ ดูด้านล่างมันเปลี่ยนป้ายเป็นคำพูดพล่อยๆเนื่องจากการบรรทุกเกินพิกัดและวิธีการส่วนตัวและ linker และคอมไพเลอร์อื่น ๆ ต้องมีชื่อที่เข้ากันได้จะทำงานร่วมกับมันในคำอื่น ๆ ABI เดียวกัน
Justin Smith

8
ฉันคิดว่าคำถามนั้นชัดเจนมาก อธิบายอย่างแม่นยำถึงรูปแบบคำตอบที่คาดหวังและยังไม่เป็นคำตอบที่น่าพอใจเพียงข้อเดียวที่สามารถยอมรับได้
ตำนาน 2k

3
@ legends2k ปัญหาของฉันคือ OP ไม่ทราบว่า ABI คืออะไร แต่ไม่ทราบว่า โปรแกรมเมอร์ส่วนใหญ่จะไม่เคยออกแบบหรือให้ ABI เพราะนั่นคืองานของนักออกแบบระบบปฏิบัติการ / แพลตฟอร์ม
JesperE

4
@JesperE: ฉันเห็นด้วยกับจุดของคุณ แต่บางที OP ต้องการทราบอย่างชัดเจนในรูปแบบที่เขาเห็นว่าเหมาะสมแม้ว่าเขา / เธออาจไม่จำเป็นต้องจัดเตรียม ABI
ตำนาน 2k

2
ฉันไม่รู้ เมื่อเร็ว ๆ นี้ในขณะที่ทำงานกับทุกสิ่งเหล่านี้ ฉันรู้ว่า ABI คืออะไร ใช่ฉันยอมรับว่าแม่แบบของฉันมีข้อผิดพลาด มันไม่เหมาะสมที่จะใส่ ABI ให้พอดีกับแม่แบบของฉัน ขอบคุณ @ JasperE มันต้องใช้ประสบการณ์การทำงานเพื่อตระหนักถึงคำตอบของคุณ
กรงเล็บ

คำตอบ:


534

วิธีหนึ่งที่ง่ายต่อการเข้าใจ "ABI" คือการเปรียบเทียบกับ "API"

คุณคุ้นเคยกับแนวคิดของ API แล้ว หากคุณต้องการใช้คุณสมบัติของ, พูด, ห้องสมุดบางส่วนหรือระบบปฏิบัติการของคุณคุณจะตั้งโปรแกรมกับ API API ประกอบด้วยชนิดข้อมูล / โครงสร้างค่าคงที่ฟังก์ชัน ฯลฯ ที่คุณสามารถใช้ในรหัสของคุณเพื่อเข้าถึงการทำงานของส่วนประกอบภายนอกนั้น

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

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

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

ด้วยเหตุนี้นักพัฒนาซอฟต์แวร์มักจะพยายามทำให้ ABI คงที่ (เพื่อลดการหยุดชะงัก) การรักษาความเสถียร ABI หมายถึงการไม่เปลี่ยนอินเทอร์เฟซฟังก์ชัน (ชนิดคืนและหมายเลขชนิดและลำดับของอาร์กิวเมนต์) คำจำกัดความของประเภทข้อมูลหรือโครงสร้างข้อมูลค่าคงที่ที่กำหนด ฯลฯ ฟังก์ชันและชนิดข้อมูลใหม่สามารถเพิ่มได้ เหมือน. ตัวอย่างเช่นหากไลบรารีของคุณใช้จำนวนเต็ม 32 บิตเพื่อระบุการชดเชยของฟังก์ชันและคุณเปลี่ยนเป็นจำนวนเต็ม 64 บิตรหัสที่คอมไพล์แล้วที่ใช้ไลบรารีนั้นจะไม่สามารถเข้าถึงฟิลด์นั้น (หรือการติดตามใด ๆ ) อย่างถูกต้อง . การเข้าถึงสมาชิกโครงสร้างข้อมูลจะถูกแปลงเป็นที่อยู่หน่วยความจำและออฟเซ็ตในระหว่างการรวบรวมและหากโครงสร้างข้อมูลเปลี่ยนแปลง

ABI ไม่จำเป็นต้องเป็นสิ่งที่คุณจะให้อย่างชัดเจนเว้นแต่ว่าคุณกำลังออกแบบระบบระดับต่ำมาก มันไม่ได้เป็นภาษาเฉพาะเนื่องจาก (ตัวอย่าง) แอปพลิเคชัน C และแอปพลิเคชัน Pascal สามารถใช้ ABI เดียวกันหลังจากที่รวบรวม

แก้ไข:เกี่ยวกับคำถามของคุณเกี่ยวกับบทที่เกี่ยวกับรูปแบบไฟล์ ELF ในเอกสาร SysV ABI: เหตุผลที่ข้อมูลนี้รวมอยู่เนื่องจากรูปแบบ ELF กำหนดอินเตอร์เฟสระหว่างระบบปฏิบัติการและแอปพลิเคชัน เมื่อคุณบอกให้ระบบปฏิบัติการรันโปรแกรมก็คาดว่าโปรแกรมจะได้รับการจัดรูปแบบในลักษณะที่แน่นอนและ (ตัวอย่าง) คาดว่าส่วนแรกของไบนารีจะเป็นส่วนหัวของเอลฟ์ที่มีข้อมูลบางอย่างที่หน่วยความจำที่เฉพาะเจาะจง นี่คือวิธีที่แอปพลิเคชันสื่อสารข้อมูลสำคัญเกี่ยวกับตัวเองไปยังระบบปฏิบัติการ หากคุณสร้างโปรแกรมในรูปแบบไบนารีที่ไม่ใช่เอลฟ์ (เช่น a.out หรือ PE) ระบบปฏิบัติการที่คาดว่าแอปพลิเคชันที่จัดรูปแบบ ELF จะไม่สามารถตีความไฟล์ไบนารีหรือเรียกใช้แอปพลิเคชันได้

IIRC, Windows ปัจจุบันใช้รูปแบบพกพา (หรือ PE) มีลิงก์ในส่วน "ลิงก์ภายนอก" ของหน้า Wikipedia นั้นพร้อมข้อมูลเพิ่มเติมเกี่ยวกับรูปแบบ PE

นอกจากนี้เกี่ยวกับบันทึกย่อของคุณเกี่ยวกับ mangling ชื่อ C ++: เมื่อค้นหาฟังก์ชันในไฟล์ไลบรารีโดยทั่วไปฟังก์ชันจะค้นหาตามชื่อ C ++ อนุญาตให้คุณโอเวอร์โหลดชื่อฟังก์ชันได้ดังนั้นชื่อเพียงอย่างเดียวไม่เพียงพอที่จะระบุฟังก์ชัน C ++ คอมไพเลอร์มีวิธีการของตัวเองในการจัดการกับเรื่องนี้ภายในเรียกชื่อ mangling ABI สามารถกำหนดวิธีมาตรฐานในการเข้ารหัสชื่อของฟังก์ชั่นเพื่อให้โปรแกรมที่สร้างด้วยภาษาอื่นหรือคอมไพเลอร์สามารถค้นหาสิ่งที่ต้องการ เมื่อคุณใช้extern "c"ในโปรแกรม C ++ คุณกำลังสั่งให้คอมไพเลอร์ใช้วิธีการบันทึกชื่อที่ซอฟต์แวร์อื่นเข้าใจได้


2
@bta ขอบคุณสำหรับคำตอบที่ดี การประชุมที่เรียกว่าเป็นประเภทของ ABI หรือไม่? ขอบคุณ
camino

37
คำตอบที่ดี ยกเว้นสิ่งนี้ไม่ใช่สิ่งที่ ABI เป็น ABI เป็นชุดของกฎที่กำหนดการประชุมที่เรียกและกฎสำหรับการจัดโครงสร้าง Pascal ส่งผ่านอาร์กิวเมนต์บนสแต็กในลำดับย้อนกลับจากแอ็พพลิเคชัน C ดังนั้น pascal และ C คอมไพเลอร์จะไม่คอมไพล์ไปที่ ABI เดียวกัน มาตรฐานที่เกี่ยวข้องสำหรับ C และ Pascal คอมไพเลอร์โดยปริยายมั่นใจว่าจะเป็นเช่นนี้ คอมไพเลอร์ C ++ ไม่สามารถกำหนดวิธี "มาตรฐาน" เพื่อรวมชื่อได้เนื่องจากไม่มีวิธีมาตรฐาน แบบแผนชื่อ mangling c ++ ไม่เข้ากันระหว่างคอมไพเลอร์ C ++ เมื่อมีคอมไพเลอร์ C ++ ที่แข่งขันกันบน Windows
Robin Davies

1
แน่นอนยังเห็นautotools.io/libtool/version.htmlและfedoramagazine.org/ …
Pacerier

1
@RobinDavies: บนแพลตฟอร์มที่คอมไพเลอร์ Pascal จะเรียกฟังก์ชั่นป๊อปอาร์กิวเมนต์ที่กำหนดโดยผู้เรียกของพวกเขาคอมไพเลอร์ C โดยทั่วไปจะกำหนดวิธีการที่โปรแกรมเมอร์สามารถระบุว่าฟังก์ชั่นควรใช้หรือควรคาดว่าจะใช้ ภาษาปาสคาลคอมไพเลอร์แม้ว่าโดยทั่วไปแล้วคอมไพเลอร์ C โดยทั่วไปจะใช้แบบแผนที่เรียกว่าฟังก์ชั่นทิ้งไว้ในกองอะไรที่วางไว้โดยโทรของพวกเขา
supercat

ฉันสามารถพูดได้ว่าไฟล์ obj ที่สร้างโดย C compiler มี ABIs หรือไม่?
Mitu Raj

144

หากคุณรู้จักการประกอบและวิธีการทำงานของสิ่งต่าง ๆ ในระดับระบบปฏิบัติการคุณกำลังปฏิบัติตาม ABI ที่แน่นอน ABI ควบคุมสิ่งต่างๆเช่นวิธีการส่งผ่านพารามิเตอร์โดยที่วางค่าส่งคืน สำหรับแพลตฟอร์มจำนวนมากมี ABI เพียงตัวเดียวให้เลือกและในกรณีเหล่านั้น ABI เป็นเพียง "วิธีการทำงานต่าง ๆ "

อย่างไรก็ตาม ABI ยังควบคุมสิ่งต่าง ๆ เช่นวิธีการวางคลาส / วัตถุใน C ++ สิ่งนี้จำเป็นถ้าคุณต้องการส่งผ่านการอ้างอิงวัตถุข้ามขอบเขตของโมดูลหรือถ้าคุณต้องการผสมรหัสที่คอมไพล์ด้วยคอมไพเลอร์ต่าง ๆ

นอกจากนี้หากคุณมีระบบปฏิบัติการ 64 บิตซึ่งสามารถใช้งานไบนารีแบบ 32 บิตได้คุณจะมี ABIs ที่แตกต่างกันสำหรับรหัส 32- และ 64 บิต

โดยทั่วไปรหัสใด ๆ ที่คุณเชื่อมโยงไปยังไฟล์ที่เรียกใช้งานได้นั้นจะต้องสอดคล้องกับ ABI เดียวกัน หากคุณต้องการสื่อสารระหว่างรหัสโดยใช้ ABIs ที่แตกต่างกันคุณต้องใช้ RPC หรือโปรโตคอลการทำให้เป็นอนุกรมในบางรูปแบบ

ฉันคิดว่าคุณพยายามอย่างหนักที่จะบีบอินเทอร์เฟซชนิดต่าง ๆ ลงในชุดคุณลักษณะคงที่ ตัวอย่างเช่นอินเทอร์เฟซไม่จำเป็นต้องแบ่งออกเป็นผู้บริโภคและผู้ผลิต อินเทอร์เฟซเป็นเพียงแบบแผนที่เอนทิตีสองโต้ตอบ

ABIs สามารถ (บางส่วน) ISA ผู้ไม่เชื่อเรื่องพระเจ้า บางแง่มุม (เช่นการประชุมที่เรียก) ขึ้นอยู่กับ ISA ในขณะที่แง่มุมอื่น ๆ (เช่นเค้าโครงคลาส C ++) ไม่ได้

ABI ที่กำหนดไว้อย่างดีมีความสำคัญมากสำหรับผู้เขียนคอมไพเลอร์ หากไม่มี ABI ที่กำหนดไว้อย่างดีมันจะเป็นไปไม่ได้ที่จะสร้างรหัสที่ทำงานร่วมกันได้

แก้ไข: หมายเหตุบางประการที่จะชี้แจง:

  • "Binary" ใน ABI ไม่ได้ยกเว้นการใช้สตริงหรือข้อความ ถ้าคุณต้องการเชื่อมโยง DLL ที่ส่งออกคลาส C ++ ที่ใดที่หนึ่งในนั้นวิธีการและลายเซ็นประเภทต้องถูกเข้ารหัส นั่นคือที่มาของชื่อ c ++ mangling
  • เหตุผลที่คุณไม่เคยให้ ABI ก็คือโปรแกรมเมอร์ส่วนใหญ่จะไม่ทำเช่นนั้น ABIs จัดทำโดยคนเดียวกันที่ออกแบบแพลตฟอร์ม (เช่นระบบปฏิบัติการ) และโปรแกรมเมอร์น้อยมากที่จะได้รับสิทธิ์ในการออกแบบ ABI ที่ใช้กันอย่างแพร่หลาย

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

2
@jesperE "ABI ควบคุมสิ่งต่าง ๆ เช่นวิธีการส่งผ่านพารามิเตอร์โดยที่ค่าส่งคืนถูกวางไว้" อ้างถึง "cdecl, stdcall, fastcall, pascal" ใช่ไหม
camino

3
ใช่. ชื่อที่เหมาะสมคือ "การเรียกแบบแผน" ซึ่งเป็นส่วนหนึ่งของ ABI en.wikipedia.org/wiki/X86_calling_conventions
JesperE

4
นี้เป็นที่ถูกต้องและแม่นยำคำตอบโดยไม่ฟุ่มเฟื่อย (แทนที่จะเสียง )!
Nawaz

ฉันขอแนะนำให้เขียนชุดประกอบเล็กน้อย สิ่งนี้จะช่วยให้ผู้คนเข้าใจ ABI ในลักษณะที่เป็นรูปธรรมมากขึ้น
KunYu Tsai

40

ที่จริงคุณไม่จำเป็นต้องมี ABI เลย -

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

ข้อมูลสรุปที่เกินความจริง:

API: "นี่คือฟังก์ชั่นทั้งหมดที่คุณสามารถโทรได้"

ABI: "นี่คือวิธีการเรียกใช้ฟังก์ชั่น"

ABI เป็นชุดของกฎที่คอมไพเลอร์และลิงเกอร์จะปฏิบัติตามเพื่อรวบรวมโปรแกรมของคุณเพื่อให้ทำงานได้อย่างถูกต้อง ABIs ครอบคลุมหลายหัวข้อ:

  • เนื้อหาที่ใหญ่ที่สุดและสำคัญที่สุดของ ABI คือมาตรฐานการเรียกโพรซีเดอร์ซึ่งบางครั้งเรียกว่า "แผนการประชุม" ระเบียบการเรียกมาตรฐานสร้างวิธีการที่ "ฟังก์ชั่น" ถูกแปลเป็นรหัสประกอบ
  • ABIs ยังกำหนดวิธีการที่ชื่อของฟังก์ชั่นที่เปิดเผยในห้องสมุดควรจะเป็นตัวแทนเพื่อให้รหัสอื่นสามารถเรียกห้องสมุดเหล่านั้นและรู้ว่าสิ่งที่ควรจะส่งผ่านข้อโต้แย้ง สิ่งนี้เรียกว่า "name mangling"
  • ABIs ยังกำหนดชนิดของชนิดข้อมูลที่สามารถใช้วิธีการจัดตำแหน่งและรายละเอียดระดับต่ำอื่น ๆ

มองลึกลงไปที่การประชุมที่เรียกซึ่งฉันคิดว่าเป็นแกนหลักของ ABI:

ตัวเครื่องไม่มีแนวคิดของ "ฟังก์ชั่น" _MyFunction1:เมื่อคุณเขียนฟังก์ชั่นในภาษาระดับสูงเช่นคคอมไพเลอร์สร้างบรรทัดของรหัสการชุมนุมเช่น นี่คือป้ายกำกับซึ่งในที่สุดจะได้รับการแก้ไขเป็นที่อยู่โดยผู้ประกอบ ป้ายกำกับนี้ทำเครื่องหมาย "เริ่มต้น" ของ "ฟังก์ชั่น" ของคุณในรหัสการประกอบ ในโค้ดระดับสูงเมื่อคุณ "เรียก" ฟังก์ชั่นนั้นสิ่งที่คุณกำลังทำอยู่จริงๆคือทำให้ CPU ข้ามไปยังที่อยู่ของป้ายกำกับนั้นและดำเนินการต่อที่นั่น

ในการเตรียมตัวสำหรับการกระโดดคอมไพเลอร์ต้องทำสิ่งต่าง ๆ ที่สำคัญ ระเบียบการเรียกเป็นเหมือนรายการตรวจสอบที่คอมไพเลอร์ติดตามทำสิ่งนี้ทั้งหมด:

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

มี ABI / การประชุมที่เรียกแตกต่างกันมากมาย บางคนหลักคือ:

  • สำหรับซีพียู x86 หรือ x86-64 (สภาพแวดล้อมแบบ 32 บิต):
    • cdecl
    • stdcall
    • fastcall
    • VECTORCALL
    • THISCALL
  • สำหรับ CPU x86-64 (สภาพแวดล้อม 64 บิต):
    • SystemV
    • MSNATIVE
    • VECTORCALL
  • สำหรับ ARM CPU (32 บิต)
    • AAPCs
  • สำหรับ ARM CPU (64 บิต)
    • AAPCS64

นี่คือหน้าเพจที่ยอดเยี่ยมที่แสดงความแตกต่างในแอสเซมบลีที่สร้างขึ้นเมื่อรวบรวมสำหรับ ABIs ที่แตกต่างกัน

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

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


19

application binary interface (ABI) นั้นคล้ายกับ API แต่ฟังก์ชั่นนั้นไม่สามารถเข้าถึงผู้เรียกได้ในระดับซอร์สโค้ด การเข้าถึงแบบไบนารีเท่านั้นที่สามารถเข้าถึงได้ / พร้อมใช้งาน

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

ฟังก์ชั่น: กำหนดกลไก / มาตรฐานเพื่อให้การเรียกใช้ฟังก์ชั่นเป็นอิสระจากภาษาที่ใช้งานหรือคอมไพเลอร์ / linker / toolchain ที่เฉพาะเจาะจง จัดเตรียมกลไกที่อนุญาตให้ใช้ JNI หรืออินเตอร์เฟส Python-C เป็นต้น

เอนทิตีที่มีอยู่: ฟังก์ชั่นในรูปแบบรหัสเครื่อง

ผู้บริโภค: ฟังก์ชั่นอื่น (รวมถึงหนึ่งในภาษาอื่นรวบรวมโดยคอมไพเลอร์อื่นหรือเชื่อมโยงโดย linker อื่น)


ทำไม ABI จะถูกกำหนดโดยสถาปัตยกรรม? เหตุใดระบบปฏิบัติการต่าง ๆ ในสถาปัตยกรรมเดียวกันจึงไม่สามารถกำหนด ABIs ที่แตกต่างกันได้
Andreas Haferburg

10

ฟังก์ชั่น: ชุดของสัญญาที่มีผลต่อคอมไพเลอร์ผู้เขียนชุดประกอบตัวเชื่อมโยงและระบบปฏิบัติการ สัญญาระบุวิธีการจัดวางฟังก์ชั่นโดยที่พารามิเตอร์ถูกส่งผ่านวิธีการส่งผ่านพารามิเตอร์วิธีการทำงานของฟังก์ชันส่งคืน โดยทั่วไปจะมีลักษณะเฉพาะสำหรับ tuple (สถาปัตยกรรมโปรเซสเซอร์, ระบบปฏิบัติการ)

เอนทิตีที่มีอยู่: โครงร่างพารามิเตอร์ความหมายฟังก์ชันการจัดสรรการลงทะเบียน ตัวอย่างเช่นสถาปัตยกรรม ARM มี ABIs จำนวนมาก (APCS, EABI, GNU-EABI, ไม่เป็นไรกรณีประวัติศาสตร์) - การใช้ ABI แบบผสมจะส่งผลให้รหัสของคุณไม่ทำงานเมื่อโทรข้ามเขตแดน

ผู้บริโภค: คอมไพเลอร์, ผู้เขียนชุดประกอบ, ระบบปฏิบัติการ, สถาปัตยกรรมเฉพาะของ CPU

ใครต้องการรายละเอียดเหล่านี้ คอมไพเลอร์นักเขียนแอสเซมบลีตัวเชื่อมโยงที่สร้างรหัส (หรือข้อกำหนดการจัดตำแหน่ง) ระบบปฏิบัติการ (การจัดการขัดจังหวะอินเทอร์เฟซ syscall) หากคุณเขียนโปรแกรมการชุมนุมคุณจะสอดคล้องกับ ABI!

ชื่อ c ++ mangling เป็นกรณีพิเศษ - เป็นตัวเชื่อมโยงและตัวเชื่อมโยงแบบไดนามิกปัญหาศูนย์กลาง - ถ้าชื่อ mangling ไม่ได้มาตรฐานการเชื่อมโยงแบบไดนามิกจะไม่ทำงาน ต่อจากนี้ไป C ++ ABI จะเรียกว่า C ++ ABI ไม่ใช่ปัญหาระดับตัวเชื่อมโยง แต่เป็นปัญหาการสร้างรหัสแทน เมื่อคุณมีไบนารี่ C ++ เป็นไปไม่ได้ที่จะทำให้มันเข้ากันได้กับ C ++ ABI อื่น (ชื่อ mangling, การจัดการข้อยกเว้น) โดยไม่ต้องคอมไพล์ใหม่จากแหล่งที่มา

ELF เป็นรูปแบบไฟล์สำหรับการใช้งานโหลดเดอร์และลิงค์ลิงเกอร์แบบไดนามิก ELF เป็นรูปแบบคอนเทนเนอร์สำหรับรหัสไบนารีและข้อมูลและเช่นนั้นระบุ ABI ของชิ้นส่วนของรหัส ฉันไม่คิดว่าเอลฟ์จะเป็น ABI ในแง่ที่เข้มงวดเนื่องจากโปรแกรม PE ไม่ได้เป็น ABI

ABIs ทั้งหมดเป็นชุดคำสั่งเฉพาะ ARM ABI จะไม่เข้าท่ากับโปรเซสเซอร์ MSP430 หรือ x86_64

Windows มี ABIs หลายตัวตัวอย่างเช่น fastcall และ stdcall เป็น ABIs ที่ใช้กันทั่วไปสองรายการ syscall ABI นั้นแตกต่างกันอีกครั้ง


9

อย่างน้อยให้ฉันตอบคำถามของคุณ ด้วยตัวอย่างว่า Linux ABI ส่งผลกระทบต่อระบบการโทรได้อย่างไรและทำไมจึงมีประโยชน์

Systemcall เป็นวิธีสำหรับโปรแกรม userspace เพื่อถาม kernelspace สำหรับบางสิ่งบางอย่าง มันทำงานได้โดยการใส่รหัสตัวเลขสำหรับการโทรและการโต้แย้งในการลงทะเบียนและก่อให้เกิดการขัดจังหวะ กว่าสวิตช์เกิดขึ้นกับ kernelspace และเคอร์เนลค้นหารหัสตัวเลขและอาร์กิวเมนต์จัดการคำขอส่งผลกลับมาในรีจิสเตอร์และทริกเกอร์สวิตช์กลับไปที่ userspace สิ่งนี้จำเป็นเช่นเมื่อแอปพลิเคชันต้องการจัดสรรหน่วยความจำหรือเปิดไฟล์ (syscalls "brk" และ "open")

ตอนนี้ syscalls มีชื่อสั้น ๆ "brk" ฯลฯ และ opcodes ที่เกี่ยวข้องเหล่านี้ถูกกำหนดไว้ในไฟล์ส่วนหัวที่เฉพาะเจาะจงของระบบ ตราบใดที่ opcodes เหล่านี้ยังคงเหมือนเดิมคุณสามารถเรียกใช้โปรแกรม userland ที่คอมไพล์แล้วด้วยเคอร์เนลที่อัพเดตที่แตกต่างกันโดยไม่ต้องคอมไพล์ใหม่ ดังนั้นคุณมีอินเทอร์เฟซที่ใช้โดยไบนารีที่คอมไพล์แล้วดังนั้น ABI


4

ในการเรียกรหัสในไลบรารีที่แชร์หรือรหัสการโทรระหว่างหน่วยการรวบรวมไฟล์วัตถุจะต้องมีป้ายกำกับสำหรับการโทร C ++ กำหนดชื่อของเลเบลเมธอดเพื่อบังคับใช้การซ่อนข้อมูลและอนุญาตสำหรับเมธอดที่โอเวอร์โหลด นี่คือเหตุผลที่คุณไม่สามารถผสมไฟล์จากคอมไพเลอร์ C ++ ที่แตกต่างกันได้เว้นแต่จะสนับสนุน ABI เดียวกันอย่างชัดเจน


4

วิธีที่ดีที่สุดในการจำแนกความแตกต่างระหว่าง ABI และ API คือการรู้ว่าทำไมและอะไรที่ใช้สำหรับ:

สำหรับ x86-64 โดยทั่วไปจะมีหนึ่ง ABI (และสำหรับ x86 32- บิตมีอีกชุดหนึ่ง):

http://www.x86-64.org/documentation/abi.pdf

https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html

http://people.freebsd.org/~obrien/amd64-elf-abi.pdf

Linux + FreeBSD + MacOSX ตามด้วยการเปลี่ยนแปลงเล็กน้อย และ Windows x64 มี ABI ของตัวเอง:

http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/

รู้จัก ABI และสมมติว่าคอมไพเลอร์อื่น ๆ ติดตามมันเช่นกันจากนั้นไบนารีก็รู้วิธีการเรียกซึ่งกันและกัน (โดยเฉพาะ API ของไลบรารี) และส่งผ่านพารามิเตอร์ไปยังสแต็กหรือโดยการลงทะเบียนเป็นต้นหรือสิ่งที่รีจิสเตอร์จะเปลี่ยนแปลง โดยพื้นฐานความรู้เหล่านี้จะช่วยให้ซอฟต์แวร์สามารถทำงานร่วมกันได้ การทราบลำดับของรูปแบบการลงทะเบียน / สแต็กฉันสามารถรวมซอฟต์แวร์ที่แตกต่างกันที่เขียนในชุดประกอบเข้าด้วยกันได้อย่างง่ายดายโดยไม่มีปัญหามาก

แต่ API นั้นแตกต่างกัน:

มันเป็นชื่อฟังก์ชั่นระดับสูงที่มีการกำหนดอาร์กิวเมนต์เช่นว่าหากชิ้นส่วนซอฟต์แวร์ที่แตกต่างกันสร้างโดยใช้ API เหล่านี้อาจจะสามารถโทรหากัน แต่ต้องปฏิบัติตามข้อกำหนดเพิ่มเติมของ SAME ABI

ตัวอย่างเช่น Windows เคยเป็น POSIX API ที่เข้ากันได้:

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

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

และ Linux ก็เป็นไปตาม POSIX เช่นกัน แต่ไบนารีไม่สามารถเคลื่อนย้ายและวิ่งได้ทันที แต่เนื่องจากพวกเขาใช้ชื่อเดียวกันใน API ที่สอดคล้องกับ POSIX คุณสามารถใช้ซอฟต์แวร์เดียวกันใน C คอมไพล์ใหม่ในระบบปฏิบัติการที่แตกต่างกันและเรียกใช้ทันที

API มีไว้เพื่อให้ง่ายต่อการรวมซอฟต์แวร์ - ขั้นตอนการรวบรวมล่วงหน้า ดังนั้นหลังจากการรวบรวมซอฟต์แวร์อาจดูแตกต่างอย่างสิ้นเชิง - ถ้า ABI นั้นแตกต่างกัน

ABI หมายถึงการกำหนดการรวมซอฟต์แวร์ที่แน่นอนในระดับไบนารี / แอสเซมบลี


แบบแผนการเรียก Windows x86-64 ไม่ได้ใช้แบบแผนการเรียก SysV ที่ระบบปฏิบัติการ x86-64 อื่น ๆ ทั้งหมดใช้ Linux / OS X / FreeBSD ทั้งหมดใช้รูปแบบการโทรเดียวกัน แต่ไม่แชร์ ABI แบบเต็ม ABI ของระบบปฏิบัติการรวมถึงหมายเลขโทรศัพท์ของระบบ เช่นfreebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/ …บอกว่านั่นSYS_execveคือ 11 ใน 32bit linux แต่ 59 ใน FreeBSD
Peter Cordes

ขอบคุณสำหรับความคิดเห็นของคุณฉันได้แก้ไขความคิดเห็นของฉันเพื่อตอบความแตกต่างระหว่าง ABI และ API ให้ดีขึ้น
Peter Teoh

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

"ชั้นความเข้ากันได้กับ FreeBSD" ไม่เคยได้ยินเรื่องนี้ คุณสามารถชี้ไปที่ซอร์สโค้ดเคอร์เนล linux ที่เกี่ยวข้องได้หรือไม่? แต่กลับทำอยู่แล้ว: freebsd.org/doc/en_US.ISO8859-1/books/handbook/linuxemu.html
Peter Teoh

ไม่ใช่สิ่งที่ฉันใช้ ฉันคิดว่ามีบางสิ่งที่มีอยู่เช่นนี้ แต่อาจจะไม่ได้อีกต่อไป tldp.org/HOWTO/Linux+FreeBSD-6.htmlบอกว่าไม่มีการระบายออกมาและวิธีการใช้นั้นมาจากปี 2000 xD unix.stackexchange.com/questions/172038/…ยืนยันว่ามันถูกทิ้งร้างและไม่เคยทำซ้ำ (เนื่องจากไม่มีใครต้องการให้มันแย่พอที่จะทำให้เสร็จ) สามารถตั้งค่าpersonality(2) PER_BSDฉันคิดว่าฉันจำได้ว่าเห็นpersonality(PER_LINUX)ในstraceการส่งออกตลอดเวลา แต่ 64bit ทันสมัยไบนารีลินุกซ์ไม่ทำอย่างนั้นอีกต่อไป
Peter Cordes

4

Linux shared library ตัวอย่าง ABI ที่รันได้น้อยที่สุด

ในบริบทของไลบรารีที่ใช้ร่วมกันความหมายที่สำคัญที่สุดของ "การมี ABI ที่เสถียร" คือคุณไม่จำเป็นต้องคอมไพล์โปรแกรมของคุณอีกครั้งหลังจากที่ไลบรารีมีการเปลี่ยนแปลง

ตัวอย่างเช่น:

  • ถ้าคุณกำลังขายไลบรารี่ที่แชร์คุณจะบันทึกผู้ใช้ของคุณไม่ให้คอมไพล์ซ้ำทุกสิ่งที่ขึ้นอยู่กับไลบรารี่ของคุณสำหรับทุก ๆ รีลีสใหม่

  • หากคุณกำลังขายโปรแกรมโอเพนซอร์ซที่ขึ้นอยู่กับห้องสมุดสาธารณะที่มีอยู่ในการแจกจ่ายของผู้ใช้คุณสามารถปล่อยและทดสอบ prebuilts ได้น้อยลงถ้าคุณมั่นใจว่า ABI นั้นมีเสถียรภาพในระบบปฏิบัติการเป้าหมายบางเวอร์ชัน

    สิ่งนี้มีความสำคัญเป็นพิเศษในกรณีของไลบรารีมาตรฐาน C ซึ่งมีหลายโปรแกรมในระบบของคุณเชื่อมโยงไปถึง

ตอนนี้ฉันต้องการให้ตัวอย่างที่สามารถรันได้อย่างเป็นรูปธรรมน้อยที่สุดในเรื่องนี้

main.c

#include <assert.h>
#include <stdlib.h>

#include "mylib.h"

int main(void) {
    mylib_mystruct *myobject = mylib_init(1);
    assert(myobject->old_field == 1);
    free(myobject);
    return EXIT_SUCCESS;
}

mylib.c

#include <stdlib.h>

#include "mylib.h"

mylib_mystruct* mylib_init(int old_field) {
    mylib_mystruct *myobject;
    myobject = malloc(sizeof(mylib_mystruct));
    myobject->old_field = old_field;
    return myobject;
}

mylib.h

#ifndef MYLIB_H
#define MYLIB_H

typedef struct {
    int old_field;
} mylib_mystruct;

mylib_mystruct* mylib_init(int old_field);

#endif

รวบรวมและทำงานได้ดีกับ:

cc='gcc -pedantic-errors -std=c89 -Wall -Wextra'
$cc -fPIC -c -o mylib.o mylib.c
$cc -L . -shared -o libmylib.so mylib.o
$cc -L . -o main.out main.c -lmylib
LD_LIBRARY_PATH=. ./main.out

ตอนนี้สมมติว่าสำหรับ v2 ห้องสมุดของเราต้องการที่จะเพิ่มข้อมูลใหม่ที่จะเรียกว่าmylib_mystructnew_field

หากเราเพิ่มฟิลด์ก่อนหน้าold_fieldดังเช่นใน:

typedef struct {
    int new_field;
    int old_field;
} mylib_mystruct;

และสร้างไลบรารีขึ้นใหม่ แต่ไม่ใช่main.outจากนั้นการยืนยันล้มเหลว!

นี่เป็นเพราะสาย:

myobject->old_field == 1

ได้สร้างชุดประกอบที่พยายามเข้าถึงโครงสร้างแรกintซึ่งตอนนี้new_fieldแทนที่จะเป็นชุดที่คาดold_fieldไว้

ดังนั้นการเปลี่ยนแปลงนี้ทำลาย ABI

อย่างไรก็ตามหากเราเพิ่มnew_fieldหลังจากold_field:

typedef struct {
    int old_field;
    int new_field;
} mylib_mystruct;

จากนั้นแอสเซมบลีที่สร้างขึ้นเก่ายังคงเข้าถึงโครงสร้างแรกintและโปรแกรมยังคงทำงานได้เพราะเราทำให้ ABI คงที่

นี่คือรุ่นโดยอัตโนมัติอย่างเต็มที่ของตัวอย่างนี้บน GitHub

อีกวิธีหนึ่งในการรักษาความเสถียรของ ABI นี้ก็คือการรักษาmylib_mystructในลักษณะทึบแสงและเข้าถึงสาขาของมันผ่านผู้ช่วยวิธีการเท่านั้น สิ่งนี้ทำให้ง่ายต่อการรักษา ABI ให้คงที่ แต่จะมีค่าใช้จ่ายด้านประสิทธิภาพเนื่องจากเราจะทำการเรียกใช้ฟังก์ชันมากขึ้น

API เทียบกับ ABI

ในตัวอย่างก่อนหน้านี้เป็นสิ่งที่น่าสนใจที่จะทราบว่าการเพิ่มnew_fieldก่อนหน้าold_fieldนี้ ABI ที่แตกออกมาเท่านั้น แต่ไม่ใช่ API

สิ่งนี้หมายความว่าถ้าเราคอมไพล์main.cโปรแกรมของเราซ้ำกับไลบรารี่

เราจะใช้ API แตก แต่ถ้าเราเปลี่ยนตัวอย่างเช่นฟังก์ชันของลายเซ็น:

mylib_mystruct* mylib_init(int old_field, int new_field);

เนื่องจากในกรณีนั้นmain.cจะหยุดรวบรวมทั้งหมด

Semantic API กับ Programming API

นอกจากนี้เรายังสามารถจัดประเภทการเปลี่ยนแปลง API ในประเภทที่สาม: การเปลี่ยนแปลงทางความหมาย

API ความหมายมักจะเป็นคำอธิบายภาษาธรรมชาติของสิ่งที่ควรทำ API มักจะรวมอยู่ในเอกสาร API

ดังนั้นจึงเป็นไปได้ที่จะทำลาย API ความหมายโดยไม่ทำลายตัวสร้างโปรแกรมเอง

ตัวอย่างเช่นถ้าเรามีการปรับเปลี่ยน

myobject->old_field = old_field;

ถึง:

myobject->old_field = old_field + 1;

ดังนั้นสิ่งนี้จะไม่แตกทั้งการเขียนโปรแกรม API และ ABI แต่main.cความหมาย API จะแตก

มีสองวิธีในการตรวจสอบสัญญา API โดยทางโปรแกรม:

  • ทดสอบพวงมุมกรณี ง่ายที่จะทำ แต่คุณอาจพลาด
  • การตรวจสอบอย่างเป็นทางการ ยากที่จะทำ แต่สร้างหลักฐานทางคณิตศาสตร์ของความถูกต้องเป็นหลักรวมเอกสารและการทดสอบในลักษณะ "มนุษย์" / เครื่องตรวจสอบได้! ตราบใดที่ไม่มีข้อผิดพลาดในคำอธิบายอย่างเป็นทางการของคุณแน่นอน ;-)

    แนวคิดนี้มีความสัมพันธ์อย่างใกล้ชิดกับการจัดทำคณิตศาสตร์อย่างเป็นทางการ: /math/53969/what-does-formal-mean/3297537#3297537

รายการของทุกสิ่งที่ทำลาย ABI ไลบรารีที่แบ่งใช้ C / C ++

สิ่งที่ต้องทำ: ค้นหา / สร้างรายการที่ดีที่สุด:

ตัวอย่าง Java ที่รันได้น้อยที่สุด

ความเข้ากันได้ไบนารีใน Java คืออะไร?

ทดสอบใน Ubuntu 18.10, GCC 8.2.0


3

ABI จะต้องสอดคล้องกันระหว่างผู้โทรและผู้รับสายเพื่อให้แน่ใจว่าการโทรสำเร็จ การใช้สแต็กใช้การลงทะเบียนการใช้ป๊อปอัพสต็อปตอนท้าย ทั้งหมดนี้เป็นส่วนที่สำคัญที่สุดของ ABI


3

สรุป

มีการตีความที่หลากหลายและความคิดเห็นที่ดีของเลเยอร์ที่แน่นอนที่กำหนด ABI (แอปพลิเคชันไบนารีอินเทอร์เฟซ)

ในมุมมองของฉัน ABI เป็นแบบแผนของสิ่งที่ถือว่าเป็นแพลตฟอร์ม / ที่กำหนดสำหรับ API เฉพาะ ABI เป็น "ส่วนที่เหลือ" ของการประชุมที่ "จะไม่เปลี่ยนแปลง" สำหรับ API ที่เฉพาะเจาะจงหรือที่จะได้รับการแก้ไขโดยสภาพแวดล้อมรันไทม์: ตัวจัดการเครื่องมือตัวเชื่อมโยงตัวคอมไพล์เลอร์ jvm และระบบปฏิบัติการ

การกำหนดอินเตอร์เฟส : ABI, API

หากคุณต้องการใช้ห้องสมุดเช่น Joda joda-time-<major>.<minor>.<patch>.jarเวลาที่คุณจะต้องประกาศพึ่งพา ห้องสมุดดังต่อไปนี้ปฏิบัติที่ดีที่สุดและการใช้ความหมายของรุ่น สิ่งนี้กำหนดความเข้ากันได้ของ API ในสามระดับ:

  1. Patch - คุณไม่จำเป็นต้องเปลี่ยนรหัสของคุณเลย ห้องสมุดเพิ่งแก้ไขข้อบกพร่องบางอย่าง
  2. เล็กน้อย - คุณไม่จำเป็นต้องเปลี่ยนรหัสของคุณตั้งแต่การเพิ่มเติม
  3. สำคัญ - อินเทอร์เฟซ (API) มีการเปลี่ยนแปลงและคุณอาจต้องเปลี่ยนรหัสของคุณ

เพื่อให้คุณใช้ไลบรารี่รุ่นใหม่ของไลบรารี่เดียวกันการประชุมอื่น ๆ ยังคงได้รับการเคารพ:

  • ภาษาไบนารีที่ใช้สำหรับไลบรารี (ใน Java กรณีรุ่นเป้าหมาย JVM ที่กำหนด Java bytecode)
  • การเรียกประชุม
  • การประชุม JVM
  • การเชื่อมโยงอนุสัญญา
  • อนุสัญญารันไทม์สิ่งเหล่านี้ถูกกำหนดและจัดการโดยเครื่องมือที่เราใช้

ตัวอย่าง

กรณีศึกษา Java

ตัวอย่างเช่น Java สร้างมาตรฐานของการประชุมทั้งหมดนี้ไม่ใช่ในเครื่องมือ แต่อยู่ในข้อกำหนด JVM ที่เป็นทางการ ข้อมูลจำเพาะอนุญาตให้ผู้ขายรายอื่น ๆ จัดเตรียมชุดเครื่องมือที่แตกต่างกันซึ่งสามารถแสดงผลไลบรารีที่เข้ากันได้

Java จัดทำกรณีศึกษาที่น่าสนใจอีกสองกรณีสำหรับ ABI: รุ่น Scala และเครื่องเสมือนDalvik

เครื่องเสมือน Dalvik ทำลาย ABI

Dalvik VM ต้องการ bytecode ประเภทอื่นที่ต่างจาก Java bytecode ห้องสมุด Dalvik ได้มาจากการแปลง Java bytecode (ด้วย API เดียวกัน) สำหรับ Dalvik ด้วยวิธีนี้คุณจะได้รับสองรุ่นของ API เดียวกัน: joda-time-1.7.2.jarกำหนดโดยเดิม เราสามารถโทรหาฉันและjoda-time-1.7.2.jar joda-time-1.7.2-dalvik.jarพวกเขาใช้ ABI หนึ่งที่แตกต่างกันสำหรับ Java vms มาตรฐานแบบกองซ้อน: Oracle's หนึ่ง, IBM's หนึ่ง, Java เปิดหรืออื่น ๆ ; และ ABI ที่สองคือหนึ่งใน Dalvik

สกาล่ารุ่นต่อเนื่องจะเข้ากันไม่ได้

Scala ไม่มีความเข้ากันได้ของไบนารีระหว่างรุ่น Scala รอง: 2.X ด้วยเหตุผลนี้ API เดียวกัน "io.reactivex" %% "rxscala"% "0.26.5" มีสามเวอร์ชัน (ในอนาคตเพิ่มเติม): สำหรับ Scala 2.10, 2.11 และ 2.12 มีการเปลี่ยนแปลงอย่างไร ฉันไม่รู้ตอนนี้แต่ไบนารีไม่เข้ากัน อาจเป็นรุ่นล่าสุดที่เพิ่มสิ่งต่าง ๆ ที่ทำให้ไลบรารีไม่สามารถใช้งานได้บนเครื่องเสมือนเก่าอาจเป็นสิ่งที่เกี่ยวข้องกับการเชื่อมโยง / การตั้งชื่อพารามิเตอร์

Java รุ่นที่ต่อเนื่องกันไม่เข้ากัน

Java ยังมีปัญหากับการเปิดตัว JVM ที่สำคัญ: 4,5,6,7,8,9 พวกเขามีความเข้ากันได้ย้อนหลังเท่านั้น Jvm9 รู้วิธีเรียกใช้โค้ดที่คอมไพล์ / กำหนดเป้าหมาย ( -targetตัวเลือกของ javac ) สำหรับรุ่นอื่น ๆ ทั้งหมดในขณะที่ JVM 4 ไม่รู้วิธีรันโค้ดที่กำหนดเป้าหมายสำหรับ JVM 5 สิ่งเหล่านี้ในขณะที่คุณมี joda-library หนึ่งชุด ความเข้ากันไม่ได้นี้ทำให้ระบบเรดาร์ตะโกนขอบคุณโซลูชั่นที่แตกต่าง:

  1. การกำหนดเวอร์ชันเชิงความหมาย: เมื่อไลบรารีกำหนดเป้าหมาย JVM สูงกว่าพวกเขามักจะเปลี่ยนเวอร์ชันหลัก
  2. ใช้ JVM 4 เป็น ABI และคุณก็ปลอดภัย
  3. Java 9 เพิ่มข้อมูลจำเพาะเกี่ยวกับวิธีที่คุณสามารถรวม bytecode สำหรับ JVM เป้าหมายเฉพาะในไลบรารีเดียวกัน

ทำไมฉันถึงเริ่มด้วยคำนิยาม API?

API และ ABI เป็นเพียงข้อกำหนดเกี่ยวกับวิธีที่คุณกำหนดความเข้ากันได้ ชั้นล่างทั่วไปในแง่ของความหมายระดับสูงมากมาย นั่นเป็นสาเหตุที่ทำให้การประชุมง่ายขึ้น ประเภทแรกของการประชุมเกี่ยวกับการจัดหน่วยความจำการเข้ารหัสไบต์การเรียกการประชุมการเข้ารหัส endian ขนาดใหญ่และน้อยเป็นต้นนอกจากนี้คุณยังได้รับการจัดระเบียบแบบปฏิบัติการที่ผู้อื่นอธิบายการเชื่อมโยงการประชุมรหัสไบต์กลางเช่นที่ใช้โดย Java หรือ LLVM IR ใช้โดย GCC อันดับที่สามที่คุณได้รับการจัดการเกี่ยวกับวิธีการค้นหาไลบรารีวิธีการโหลด (ดูที่ Java classloaders) ในขณะที่คุณก้าวไปสู่แนวคิดที่สูงขึ้นเรื่อย ๆ คุณจะมีการประชุมใหม่ที่คุณคิดว่าเป็น นั่นเป็นเหตุผลที่พวกเขาไม่ได้ทำให้มันไปเวอร์ชันความหมายรุ่น <major>-<minor>-<patch>-<platform/ABI>เราสามารถแก้ไขเวอร์ชันความหมายกับ นี่คือสิ่งที่เกิดขึ้นจริงแล้ว: แพลตฟอร์มที่มีอยู่แล้วrpm, dll, jar(JVM bytecode) war(JVM + เว็บเซิร์ฟเวอร์) apk, 2.11(เฉพาะรุ่น Scala) และอื่น ๆ เมื่อคุณพูดว่า APK คุณพูดถึงส่วนหนึ่งของ ABI API ของคุณแล้ว

API สามารถย้ายไปยัง ABI ที่แตกต่างกัน

ระดับสูงสุดของสิ่งที่เป็นนามธรรม (แหล่งที่เขียนด้วย API สูงสุดสามารถคอมไพล์ใหม่ / พอร์ตไปยังสิ่งที่เป็นนามธรรมในระดับที่ต่ำกว่าอื่น ๆ

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

APIs ที่ย้ายข้ามภาษา

มี APIs ที่รังเพลิงในหลายภาษาเช่นมีลำธารปฏิกิริยา โดยทั่วไปแล้วพวกเขากำหนดการแมปกับภาษา / แพลตฟอร์มเฉพาะ ฉันจะยืนยันว่า API เป็นข้อกำหนดหลักที่กำหนดอย่างเป็นทางการในภาษามนุษย์หรือแม้แต่ภาษาโปรแกรมเฉพาะ "การจับคู่" อื่น ๆ ทั้งหมดเป็น ABI ในแง่หนึ่งก็คือ API อื่น ๆ มากกว่า ABI ปกติ สิ่งเดียวกันก็เกิดขึ้นกับส่วนต่อประสาน REST


1

ในระยะสั้นและในปรัชญาสิ่งเดียวของชนิดสามารถเข้ากันได้ดีและ ABI อาจจะมองว่าเป็นชนิดที่ทำงานร่วมกันสิ่งที่ซอฟแวร์


1

ฉันก็พยายามเข้าใจ ABI และคำตอบของ JesperE ก็มีประโยชน์มาก

จากมุมมองที่ง่ายมากเราอาจพยายามเข้าใจ ABI โดยพิจารณาความเข้ากันได้ของไบนารี

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

ทีนี้ลองดูที่พื้นฐานที่สุดที่จำเป็นสำหรับไลบรารีเพื่อความเข้ากันได้ของไบนารี (สมมติว่าไม่มีการเปลี่ยนแปลงซอร์สโค้ดกับไลบรารี):

  1. สถาปัตยกรรมชุดคำสั่งที่เข้ากันได้เหมือนกัน / ย้อนหลัง (คำสั่งตัวประมวลผลโครงสร้างไฟล์ลงทะเบียนองค์กรสแต็คประเภทการเข้าถึงหน่วยความจำพร้อมกับขนาดโครงร่างและการจัดตำแหน่งประเภทข้อมูลพื้นฐานที่โปรเซสเซอร์สามารถเข้าถึงได้โดยตรง)
  2. แบบแผนการโทรเดียวกัน
  3. แบบแผนชื่อ mangling เดียวกัน (อาจจำเป็นถ้าพูดว่าโปรแกรม Fortran จำเป็นต้องเรียกใช้ฟังก์ชันไลบรารี C ++)

แน่นอนว่ามีรายละเอียดอื่น ๆ อีกมากมาย แต่นี่ก็เป็นสิ่งที่ ABI ครอบคลุมเช่นกัน

โดยเฉพาะอย่างยิ่งเพื่อตอบคำถามของคุณจากด้านบนเราสามารถอนุมาน:

ฟังก์ชัน ABI: ความเข้ากันได้ของไบนารี

เอนทิตีที่มีอยู่: โปรแกรม / ไลบรารี / OS ที่มีอยู่

ผู้บริโภค: ห้องสมุด, ระบบปฏิบัติการ

หวังว่านี่จะช่วยได้!


1

Application binary interface (ABI)

ฟังก์ชันการทำงาน:

  • การแปลจากรูปแบบของโปรแกรมเมอร์เป็นชนิดข้อมูลขนาดโดเมนการจัดตำแหน่งการประชุมที่เรียกซึ่งควบคุมวิธีการส่งผ่านอาร์กิวเมนต์ของฟังก์ชันและการคืนค่าที่ดึงมา หมายเลขการโทรของระบบและวิธีที่แอปพลิเคชันควรทำการโทรของระบบไปยังระบบปฏิบัติการ ชุดรูปแบบชื่อ mangling ของคอมไพเลอร์ภาษาระดับสูงการเผยแพร่ข้อยกเว้นและการเรียกการประชุมระหว่างคอมไพเลอร์บนแพลตฟอร์มเดียวกัน แต่ไม่ต้องการความเข้ากันได้ข้ามแพลตฟอร์ม ...

หน่วยงานที่มีอยู่:

  • บล็อกเชิงตรรกะที่มีส่วนร่วมโดยตรงในการทำงานของโปรแกรม: ALU, การลงทะเบียนวัตถุประสงค์ทั่วไป, การลงทะเบียนสำหรับการแมปหน่วยความจำ / I / O ของ I / O, ฯลฯ ...

ผู้บริโภค:

  • ภาษาลิงเกอร์โปรเซสเซอร์แอสเซมเบลอร์ ...

สิ่งเหล่านี้จำเป็นสำหรับใครก็ตามที่ต้องทำให้แน่ใจว่าการสร้างเครื่องมือโซ่ทำงานโดยรวม หากคุณเขียนหนึ่งโมดูลในภาษาแอสเซมบลีอีกโมดูลหนึ่งใน Python และแทนที่จะใช้บูทโหลดเดอร์ของคุณเองต้องการใช้ระบบปฏิบัติการโมดูล "แอปพลิเคชัน" ของคุณจะทำงานข้ามขอบเขต "ไบนารี" และต้องการข้อตกลง "อินเทอร์เฟซ" ดังกล่าว

ชื่อ c ++ mangling เนื่องจากไฟล์อ็อบเจ็กต์จากภาษาระดับสูงที่แตกต่างกันอาจจำเป็นต้องเชื่อมโยงในแอปพลิเคชันของคุณ พิจารณาใช้ไลบรารีมาตรฐาน GCC ที่ทำให้การเรียกระบบไปยัง Windows ที่สร้างด้วย Visual C ++

ELF เป็นความคาดหวังที่เป็นไปได้อย่างหนึ่งของตัวลิงก์จากไฟล์อ็อบเจ็กต์สำหรับการตีความแม้ว่า JVM อาจมีแนวคิดอื่น

สำหรับแอพ Windows RT Store ให้ลองค้นหา ARM ABI หากคุณต้องการให้โซ่เครื่องมือสร้างทำงานร่วมกัน


1

คำ ABI ใช้เพื่ออ้างถึงแนวคิดที่แตกต่าง แต่เกี่ยวข้องกันสองแนวคิด

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

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

การเปลี่ยนแปลงห้องสมุดสามารถทำลาย ABI โดยไม่ทำลาย API ลองพิจารณาตัวอย่างเช่นไลบรารีที่มีอินเตอร์เฟสเหมือนกัน

void initfoo(FOO * foo)
int usefoo(FOO * foo, int bar)
void cleanupfoo(FOO * foo)

และโปรแกรมเมอร์แอปพลิเคชันเขียนรหัสเช่น

int dostuffwithfoo(int bar) {
  FOO foo;
  initfoo(&foo);
  int result = usefoo(&foo,bar)
  cleanupfoo(&foo);
  return result;
}

โปรแกรมเมอร์แอปพลิเคชันไม่สนใจขนาดหรือเลย์เอาต์ของ FOO แต่ไบนารีแอปพลิเคชันจะลงท้ายด้วยขนาดของ hardcoded ของ foo หากโปรแกรมเมอร์ไลบรารีเพิ่มฟิลด์พิเศษลงใน foo และบางคนใช้ไลบรารีไลบรารี่ใหม่พร้อมกับแอปพลิเคชันไบนารีเก่าไลบรารีอาจทำให้การเข้าถึงหน่วยความจำเกินขอบเขต

OTOH ถ้าผู้เขียนไลบรารีได้ออกแบบ API ของตนเช่นนั้น

FOO * newfoo(void)
int usefoo(FOO * foo, int bar)
void deletefoo((FOO * foo, int bar))

และโปรแกรมเมอร์แอปพลิเคชันเขียนรหัสเช่น

int dostuffwithfoo(int bar) {
  FOO * foo;
  foo = newfoo();
  int result = usefoo(foo,bar)
  deletefoo(foo);
  return result;
}

จากนั้นแอ็พพลิเคชันไบนารีไม่จำเป็นต้องรู้อะไรเกี่ยวกับโครงสร้างของ FOO ซึ่งสามารถซ่อนอยู่ภายในไลบรารีได้ ราคาที่คุณจ่ายไปนั้นมีส่วนเกี่ยวข้องกับการดำเนินการกอง


0

ABI- Application Binary Interfaceเป็นเรื่องเกี่ยวกับการสื่อสารรหัสเครื่องในรันไทม์ระหว่างสองส่วนของโปรแกรมไบนารีเช่น - แอปพลิเคชัน, ไลบรารี, ระบบปฏิบัติการ ... ABIอธิบายถึงวิธีการบันทึกวัตถุในหน่วยความจำและวิธีการเรียกใช้ฟังก์ชั่น ( calling convention)

ตัวอย่างที่ดีของ API และ ABI เป็นระบบนิเวศ iOS ด้วยภาษาสวิฟท์

  • Application- เมื่อคุณสร้างแอปพลิเคชันด้วยภาษาที่แตกต่างกัน ตัวอย่างเช่นคุณสามารถสร้างแอปพลิเคชันโดยใช้SwiftและObjective-C[Mixing Swift และ Objective-C]

  • Application - OS- รันไทม์ - Swift runtimeและstandard librariesเป็นส่วนหนึ่งของระบบปฏิบัติการและไม่ควรรวมอยู่ในแต่ละบันเดิล (เช่นแอพ, กรอบงาน) มันเหมือนกับการใช้ Objective-C

  • Library- Module Stabilityกรณี - เวลาในการคอมไพล์ - คุณจะสามารถนำเข้าเฟรมเวิร์กที่สร้างขึ้นด้วยคอมไพเลอร์รุ่นอื่นของ Swift หมายความว่าเป็นความปลอดภัยในการสร้างไบนารีแบบปิดแหล่งที่มา (pre-build) ซึ่งจะถูกใช้โดยคอมไพเลอร์รุ่นอื่น ( .swiftinterfaceใช้กับ.swiftmodule) และคุณจะไม่ได้รับ

    Module compiled with _ cannot be imported by the _ compiler
    
  • Library- Library Evolutionกรณี

    1. เวลารวบรวม - หากมีการเปลี่ยนแปลงการพึ่งพาลูกค้าจะไม่ต้องทำการคอมไพล์ใหม่
    2. รันไทม์ - ไลบรารีระบบหรือเฟรมเวิร์กแบบไดนามิกสามารถสลับร้อนโดยใหม่

[API กับ ABI]

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