เหตุใด Windows64 จึงใช้รูปแบบการโทรที่แตกต่างจาก OS อื่น ๆ ทั้งหมดบน x86-64


110

AMD มีข้อกำหนด ABI ที่อธิบายถึงรูปแบบการโทรที่จะใช้บน x86-64 ระบบปฏิบัติการทั้งหมดทำตามยกเว้น Windows ที่มีรูปแบบการโทร x86-64 ของตัวเอง ทำไม?

มีใครรู้เหตุผลทางเทคนิคประวัติศาสตร์หรือการเมืองสำหรับความแตกต่างนี้หรือเป็นเรื่องของ NIHsyndrome หรือไม่?

ผมเข้าใจว่าระบบปฏิบัติการที่แตกต่างกันอาจมีความต้องการที่แตกต่างกันสำหรับสิ่งที่ระดับที่สูงขึ้น แต่ไม่ได้อธิบายว่าทำไมเช่นพารามิเตอร์การลงทะเบียนผ่านการสั่งซื้อบน Windows คือในขณะที่คนอื่นใช้ทุกคนrcx - rdx - r8 - r9 - rest on stackrdi - rsi - rdx - rcx - r8 - r9 - rest on stack

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

แก้ไข: สำหรับวิธีการดูเช่นรายการวิกิพีเดียและลิงก์จากที่นั่น


3
สำหรับการลงทะเบียนครั้งแรก: rcx: ecx คือพารามิเตอร์ "this" สำหรับอนุสัญญา msvc __thiscall x86 ดังนั้นอาจเป็นเพียงเพื่อความสะดวกในการย้ายคอมไพเลอร์ไปที่ x64 พวกเขาเริ่มต้นด้วย rcx เป็นตัวแรก จากนั้นทุกสิ่งทุกอย่างก็จะแตกต่างออกไปเช่นกันเป็นเพียงผลจากการตัดสินใจครั้งแรกนั้น
Chris Becke

@ คริส: ฉันได้เพิ่มการอ้างอิงไปยังเอกสารเสริม AMD64 ABI (และคำอธิบายบางส่วนว่ามันคืออะไร) ด้านล่าง
แฟรงค์

1
ฉันไม่พบเหตุผลจาก MS แต่ฉันพบการสนทนาที่นี่
phuclv

คำตอบ:


81

การเลือกอาร์กิวเมนต์สี่ตัวลงทะเบียนบน x64 - โดยทั่วไปของ UN * X / Win64

สิ่งหนึ่งที่ควรทราบเกี่ยวกับ x86 คือชื่อรีจิสเตอร์สำหรับการเข้ารหัส "หมายเลข reg" นั้นไม่ชัดเจน ในแง่ของการเข้ารหัสคำสั่ง ( ไบต์MOD R / Mโปรดดูที่http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ) ให้ลงทะเบียนหมายเลข 0 ... 7 คือ - ตามลำดับ - ?AX, ?CX, ?DX, ?BX, ?SP, ?BP, ,?SI?DI

ดังนั้นการเลือก A / C / D (regs 0..2) สำหรับค่าส่งคืนและอาร์กิวเมนต์สองตัวแรก (ซึ่งเป็น__fastcallอนุสัญญา32 บิต "คลาสสิก" ) จึงเป็นตัวเลือกเชิงตรรกะ เท่าที่เกี่ยวข้องกับ 64 บิตจะมีการเรียงลำดับ "ที่สูงกว่า" และทั้ง Microsoft และ UN * X / Linux ใช้สำหรับR8/ R9เป็นรายการแรก

การรักษาที่ในใจเลือกที่ไมโครซอฟท์RAX(ค่าตอบแทน) และRCX, RDX, R8, R9(หาเรื่อง [0..3]) เป็นตัวเลือกที่เข้าใจถ้าคุณเลือกที่สี่ลงทะเบียนสำหรับข้อโต้แย้ง

ผมไม่ทราบว่าทำไม AMD64 สหประชาชาติ * X ABI เลือกก่อนRDXRCX

การเลือกอาร์กิวเมนต์หกตัวลงทะเบียนบน x64 - UN * X เฉพาะ

UN * X บนสถาปัตยกรรม RISC ได้ทำการโต้แย้งในการลงทะเบียนโดยเฉพาะสำหรับข้อโต้แย้งหกข้อแรก(นั่นคือ PPC, SPARC, MIPS เป็นอย่างน้อย) ซึ่งอาจเป็นหนึ่งในสาเหตุสำคัญที่นักออกแบบ AMD64 (UN * X) ABI เลือกใช้รีจิสเตอร์หกตัวบนสถาปัตยกรรมนั้นด้วย

ดังนั้นหากคุณต้องการหกลงทะเบียนที่จะผ่านการขัดแย้งในและก็มีเหตุผลที่จะเลือกRCX, RDX, R8และR9สี่ของพวกเขาซึ่งอีกสองคนที่คุณควรเลือก?

Regs "สูงกว่า" ต้องการไบต์คำนำหน้าคำสั่งเพิ่มเติมเพื่อเลือกดังนั้นจึงมีขนาดคำสั่งที่ใหญ่กว่าดังนั้นคุณจึงไม่ต้องการเลือกตัวเลือกใด ๆ หากคุณมีตัวเลือก ของการลงทะเบียนแบบคลาสสิกเนื่องจากความหมายโดยนัยของRBPและRSPสิ่งเหล่านี้ไม่สามารถใช้ได้และโดยRBXปกติแล้วจะมีการใช้งานพิเศษบน UN * X (ตารางออฟเซ็ตทั่วโลก) ซึ่งดูเหมือนว่านักออกแบบ AMD64 ABI ไม่ต้องการที่จะเข้ากันไม่ได้โดยไม่จำเป็น
Ergo ทางเลือกเดียวคือRSI/ RDI.

ดังนั้นหากคุณต้องรับRSI/ RDIเป็นอาร์กิวเมนต์รีจิสเตอร์ข้อโต้แย้งใดที่ควรเป็น

ทำให้พวกเขาarg[0]และarg[1]มีข้อดีบางอย่าง ดูความคิดเห็นของ cHao
?SIและ?DIเป็นสตริงคำสั่งต้นทาง / ปลายทางตัวถูกดำเนินการและตามที่ cHao กล่าวถึงการใช้เป็นอาร์กิวเมนต์รีจิสเตอร์หมายความว่าด้วยอนุสัญญาการเรียก AMD64 UN * X strcpy()ฟังก์ชันที่ง่ายที่สุดที่เป็นไปได้ตัวอย่างเช่นประกอบด้วยคำสั่ง CPU สองคำสั่งเท่านั้นrepz movsb; retเนื่องจากต้นทาง / เป้าหมาย ที่อยู่ถูกใส่ลงในรีจิสเตอร์ที่ถูกต้องโดยผู้โทร โดยเฉพาะอย่างยิ่งในโค้ด "กาว" ระดับต่ำและคอมไพเลอร์ที่สร้างขึ้น (ลองนึกดูเช่นตัวจัดสรรฮีป C ++ บางตัวเป็นศูนย์เติมอ็อบเจ็กต์บนโครงสร้างหรือหน้าฮีปที่เติมศูนย์เคอร์เนลบนsbrk()หรือ copy-on-write pagefaults) จำนวนมากของ block copy / fill ดังนั้นจึงมีประโยชน์สำหรับโค้ดที่ใช้บ่อยเพื่อบันทึกคำสั่ง CPU สองหรือสามคำสั่งที่จะโหลดอาร์กิวเมนต์ที่อยู่ต้นทาง / ปลายทางดังกล่าวลงใน การลงทะเบียน "ถูกต้อง"

ดังนั้นในทางสหประชาชาติ * X และ Win64 จะแตกต่างกันเพียง แต่ในการที่สหประชาชาติ * X "prepends" สองอาร์กิวเมนต์เพิ่มเติมในการได้รับการแต่งตั้งอย่างเด็ดเดี่ยวRSI/ RDIลงทะเบียนเพื่อเป็นทางเลือกธรรมชาติในสี่ข้อโต้แย้งในRCX, RDX, และR8R9

นอกเหนือจากนั้น ...

มีความแตกต่างระหว่าง UN * X และ Windows x64 ABI มากกว่าแค่การแมปอาร์กิวเมนต์กับรีจิสเตอร์เฉพาะ สำหรับภาพรวมของ Win64 ตรวจสอบ:

http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx

Win64 และ AMD64 UN * X ยังแตกต่างกันอย่างมากในวิธีการใช้ stackspace บน Win64 ตัวอย่างเช่นผู้เรียกต้องจัดสรร stackspace สำหรับอาร์กิวเมนต์ของฟังก์ชันแม้ว่า args 0 ... 3 จะถูกส่งผ่านในรีจิสเตอร์ ในทางกลับกัน UN * X ฟังก์ชัน leaf (เช่นฟังก์ชันที่ไม่เรียกใช้ฟังก์ชันอื่น ๆ ) ไม่จำเป็นต้องจัดสรรสแต็กสเปซเลยหากต้องการไม่เกิน 128 ไบต์ (ใช่คุณเป็นเจ้าของและสามารถใช้ได้ สแต็คจำนวนหนึ่งโดยไม่ต้องจัดสรร ... เว้นแต่คุณจะเป็นรหัสเคอร์เนลซึ่งเป็นแหล่งที่มาของข้อบกพร่องที่ดี) ทั้งหมดนี้เป็นทางเลือกในการเพิ่มประสิทธิภาพโดยเฉพาะเหตุผลส่วนใหญ่สำหรับสิ่งเหล่านี้มีการอธิบายไว้ในการอ้างอิง ABI แบบเต็มที่อ้างอิงจากวิกิพีเดียของผู้โพสต์ต้นฉบับ


1
เกี่ยวกับชื่อรีจิสเตอร์: ไบต์คำนำหน้านั้นอาจเป็นปัจจัย แต่มันจะเป็นเหตุผลมากกว่าสำหรับ MS ที่จะเลือก rcx - rdx - rdi - rsi เป็นอาร์กิวเมนต์รีจิสเตอร์ แต่ค่าตัวเลขของแปดตัวแรกสามารถแนะนำคุณได้หากคุณกำลังออกแบบ ABI ตั้งแต่เริ่มต้น แต่ก็ไม่มีเหตุผลที่จะเปลี่ยนแปลงได้หากมี ABI ที่ดีอย่างสมบูรณ์อยู่แล้วซึ่งจะทำให้เกิดความสับสนมากขึ้นเท่านั้น
JanKanis

2
ใน RSI / RDI: คำแนะนำเหล่านี้มักจะมีการแทรกในซึ่งในกรณีนี้การเรียกประชุมจะไม่สำคัญ มิฉะนั้นจะมีเพียงสำเนาเดียว (หรืออาจไม่กี่รายการ) ของฟังก์ชันนั้นทั่วทั้งระบบดังนั้นจึงบันทึกเพียงจำนวนไบต์ทั้งหมดเท่านั้น ไม่คุ้มค่า. เกี่ยวกับความแตกต่างอื่น ๆ / call stack: ประโยชน์ของตัวเลือกที่เฉพาะเจาะจงอธิบายไว้ในการอ้างอิง ABI แต่ไม่ได้ทำการเปรียบเทียบ พวกเขาไม่ได้บอกว่าเหตุใดจึงไม่เลือกการเพิ่มประสิทธิภาพอื่น ๆ เช่นทำไม Windows ถึงไม่มีโซนสีแดงขนาด 128 ไบต์และเหตุใด AMD ABI จึงไม่มีสแต็กสล็อตพิเศษสำหรับอาร์กิวเมนต์
JanKanis

1
@cHao: ไม่. แต่พวกเขาก็เปลี่ยนมันอยู่ดี Win64 ABI แตกต่างจาก Win32 one (และไม่เข้ากันได้) และยังแตกต่างจาก AMDs ABI
JanKanis

8
@Somejan: Win64 และ Win32 __fastcallเหมือนกัน 100% สำหรับกรณีที่มีอาร์กิวเมนต์ไม่เกินสองรายการไม่เกิน 32 บิตและส่งคืนค่าไม่เกิน 32 บิต นั่นไม่ใช่ฟังก์ชันระดับเล็ก ๆ ไม่มีความเข้ากันได้แบบย้อนหลังเลยระหว่าง UN * X ABI สำหรับ i386 / amd64
แฟรงค์

2
@szx: ฉันเพิ่งพบหัวข้อรายชื่ออีเมลที่เกี่ยวข้องเมื่อเดือนพฤศจิกายน พ.ศ. 2543 และโพสต์คำตอบโดยสรุปเหตุผล โปรดทราบว่าที่อาจจะนำมาใช้วิธีการที่ไม่ได้memcpy strcpy
Peter Cordes

42

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

เป็นเรื่องที่น่าสนใจในการอ่านเธรดเก่าเหล่านั้นในรายชื่อส่งเมลของ AMD64 เนื่องจากสถาปนิกของ AMD ใช้งานอยู่ เช่นการเลือกชื่อที่ลงทะเบียนเป็นหนึ่งในส่วนที่ยาก: AMD พิจารณาเปลี่ยนชื่อเดิม 8 ลงทะเบียน r0-R7 หรือเรียกสิ่งใหม่ ๆ UAXเช่นการลงทะเบียน

นอกจากนี้ข้อเสนอแนะจากเมล็ด devs สิ่งที่ระบุที่ทำให้การออกแบบเดิมของsyscallและswapgsใช้ไม่ได้ นั่นเป็นวิธีที่ AMD อัปเดตคำสั่งเพื่อให้ได้สิ่งนี้ก่อนที่จะปล่อยชิปจริงใด ๆ เป็นที่น่าสนใจว่าในช่วงปลายปี 2000 สมมติฐานคือ Intel อาจจะไม่ใช้ AMD64


การประชุมการเรียกใช้ SysV (Linux) และการตัดสินใจเกี่ยวกับจำนวนการลงทะเบียนที่ควรเก็บรักษาไว้เมื่อเทียบกับการบันทึกผู้โทรเริ่มต้นในเดือนพฤศจิกายน พ.ศ. 2543 โดย Jan Hubicka (ผู้พัฒนา gcc) เขารวบรวม SPEC2000และดูขนาดโค้ดและจำนวนคำสั่ง กระทู้สนทนานั้นตีกลับแนวคิดเดียวกันกับคำตอบและความคิดเห็นเกี่ยวกับคำถาม SO นี้ ในเธรดที่ 2 เขาเสนอลำดับปัจจุบันว่าเหมาะสมที่สุดและหวังว่าสุดท้ายจะสร้างโค้ดที่เล็กกว่าทางเลือกอื่น

เขาใช้คำว่า "global" เพื่อหมายถึงการลงทะเบียนที่สงวนการโทรซึ่งจะต้องมีการผลัก / โผล่หากใช้

ทางเลือกของrdi, rsi, rdxขณะที่ทั้งสาม args แรกที่ได้รับแรงบันดาลใจจาก:

  • การประหยัดขนาดรหัสรองในฟังก์ชันที่เรียกใช้memsetหรือฟังก์ชันสตริง C อื่น ๆ บน args (โดยที่ gcc แทรกการดำเนินการสตริงตัวแทน?)
  • rbxถูกสงวนไว้สำหรับการโทรเนื่องจากการมี regs ที่สงวนไว้สำหรับการโทรสองรายการที่สามารถเข้าถึงได้โดยไม่มีคำนำหน้า REX (rbx และ rbp) ถือเป็นชัยชนะ สันนิษฐานว่าถูกเลือกเนื่องจากเป็น reg อื่น ๆ ที่ไม่ได้ใช้โดยปริยายโดยคำสั่งใด ๆ (สตริงตัวแทนจำนวนกะและเอาต์พุต / อินพุต mul / div สัมผัสทุกอย่าง)
  • ไม่มีการลงทะเบียนใดที่มีจุดประสงค์พิเศษที่สงวนไว้สำหรับการเรียก (ดูจุดก่อนหน้า) ดังนั้นฟังก์ชันที่ต้องการใช้คำสั่งสตริงตัวแทนหรือกะจำนวนตัวแปรอาจต้องย้ายอาร์กิวเมนต์ของฟังก์ชันไปที่อื่น แต่ไม่จำเป็นต้องบันทึก / เรียกคืนค่าของผู้โทร
  • เราพยายามหลีกเลี่ยง RCX ในช่วงต้นของลำดับเนื่องจากเป็นการลงทะเบียนที่ใช้กันทั่วไปเพื่อวัตถุประสงค์พิเศษเช่น EAX ดังนั้นจึงมีจุดประสงค์เดียวกันที่จะขาดหายไปในลำดับ นอกจากนี้ยังไม่สามารถใช้กับ syscalls ได้และเราต้องการสร้างลำดับ syscall เพื่อให้ตรงกับลำดับการเรียกฟังก์ชันให้มากที่สุด

    (พื้นหลัง: syscall/ sysretทำลายrcx(ด้วยrip) และr11(ด้วยRFLAGS) อย่างหลีกเลี่ยงไม่ได้ดังนั้นเคอร์เนลจึงไม่สามารถมองเห็นสิ่งที่อยู่ในเดิมrcxเมื่อsyscallรัน)

เคอร์เนลระบบโทร ABI ได้รับเลือกให้ตรงกับฟังก์ชั่นการโทร ABI ยกเว้นr10แทนrcxดังนั้นฟังก์ชั่นเสื้อคลุม libc เช่นmmap(2)สามารถเพียงmov %rcx, %r10/ /mov $0x9, %eaxsyscall


โปรดทราบว่ารูปแบบการโทร SysV ที่ใช้โดย i386 Linux นั้นแย่มากเมื่อเทียบกับ __vectorcall 32 บิตของ Window มันผ่านทุกอย่างในกองและผลตอบแทนเฉพาะในedx:eaxสำหรับ int64 ไม่ได้สำหรับ structs ไม่แปลกใจเลยที่จะพยายามรักษาความเข้ากันได้กับมัน เมื่อไม่มีเหตุผลที่จะไม่ทำพวกเขาก็ทำสิ่งต่าง ๆ เช่นรักษาการrbxโทรไว้เนื่องจากพวกเขาตัดสินใจว่าการมีอีกตัวใน 8 ดั้งเดิม (ที่ไม่ต้องใช้คำนำหน้า REX) นั้นดี

การทำให้ ABI ดีที่สุดมีความสำคัญในระยะยาวมากกว่าการพิจารณาอื่น ๆ ฉันคิดว่าพวกเขาทำได้ดีทีเดียว ฉันไม่แน่ใจทั้งหมดเกี่ยวกับการส่งคืนโครงสร้างที่บรรจุลงในรีจิสเตอร์แทนที่จะเป็นฟิลด์ที่แตกต่างกันใน regs ที่ต่างกัน ฉันเดาว่ารหัสที่ส่งผ่านค่าเหล่านั้นไปรอบ ๆ โดยไม่ได้ใช้งานจริงในฟิลด์จะชนะด้วยวิธีนี้ แต่การแกะกล่องเพิ่มเติมดูเหมือนจะไร้สาระ พวกเขาสามารถมีรีจิสเตอร์การส่งคืนจำนวนเต็มมากกว่าrdx:raxดังนั้นการส่งคืนโครงสร้างที่มีสมาชิก 4 คนสามารถส่งคืนใน rdi, rsi, rdx, rax หรือบางอย่าง

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


ฉันสงสัยว่านักออกแบบ Windows ABI อาจมีเป้าหมายที่จะลดความแตกต่างระหว่าง 32 และ 64 บิตเพื่อประโยชน์ของผู้คนที่ต้องพอร์ต asm จากที่หนึ่งไปยังอีกที่หนึ่งหรืออาจใช้สองสามตัว#ifdefใน ASM บางตัวเพื่อให้แหล่งข้อมูลเดียวกันสามารถสร้างได้ง่ายขึ้น ฟังก์ชันเวอร์ชัน 32 หรือ 64 บิต

การลดการเปลี่ยนแปลงใน toolchain ดูเหมือนไม่น่าเป็นไปได้ คอมไพลเลอร์ x86-64 ต้องการตารางแยกต่างหากว่ารีจิสเตอร์ใช้สำหรับอะไรและหลักการเรียกใช้คืออะไร การซ้อนทับกันเล็กน้อยกับ 32 บิตไม่น่าจะช่วยประหยัดขนาด / ความซับซ้อนของโค้ด toolchain ได้อย่างมีนัยสำคัญ


1
ฉันคิดว่าฉันได้อ่านที่ไหนสักแห่งในบล็อกของ Raymond Chen เกี่ยวกับเหตุผลในการเลือกการลงทะเบียนเหล่านั้นหลังจากการเปรียบเทียบจากฝั่ง MS แต่ฉันไม่พบอีกต่อไป อย่างไรก็ตามมีการอธิบายเหตุผลบางประการเกี่ยวกับ homezone ไว้ที่นี่blogs.msdn.microsoft.com/oldnewthing/20160623-00/?p=93735 blogs.msdn.microsoft.com/freik/2006/03/06/…
phuclv


@phuclv: ดูเพิ่มเติมการเขียนด้านล่าง ESP ถูกต้องหรือไม่ . ความคิดเห็นของ Raymond เกี่ยวกับคำตอบของฉันที่นั่นชี้ให้เห็นรายละเอียด SEH บางอย่างที่ฉันไม่รู้ซึ่งอธิบายได้ว่าทำไม x86 32/64 Windows จึงไม่มีเขตสีแดงโดยพฤตินัย โพสต์บล็อกของเขามีบางกรณีที่เป็นไปได้สำหรับความเป็นไปได้ในตัวจัดการหน้ารหัสเดียวกันที่ฉันพูดถึงในคำตอบนั้น :) ใช่แล้วเรย์มอนด์อธิบายได้ดีกว่าที่ฉันทำ (ไม่น่าแปลกใจเพราะฉันเริ่มจากการรู้น้อยมากเกี่ยวกับ Windows) และตารางขนาดโซนสีแดงสำหรับ non-x86 นั้นเรียบร้อยมาก
Peter Cordes

13

โปรดจำไว้ว่าตอนแรก Microsoft "ไม่เป็นทางการอย่างเป็นทางการต่อความพยายามของ AMD64 ในยุคแรก" (จาก"A History of Modern 64-bit Computing"โดย Matthew Kerner และ Neil Padgett) เนื่องจากเป็นพันธมิตรที่แข็งแกร่งกับ Intel ในสถาปัตยกรรม IA64 ฉันคิดว่านั่นหมายความว่าแม้ว่าพวกเขาจะเปิดกว้างในการทำงานร่วมกับวิศวกร GCC ใน ABI เพื่อใช้ทั้งบน Unix และ Windows แต่พวกเขาก็ไม่ได้ทำเช่นนั้นเพราะจะหมายถึงการสนับสนุนความพยายามของ AMD64 ต่อสาธารณะเมื่อพวกเขาไม่มี ยังทำอย่างเป็นทางการ (และอาจทำให้ Intel ไม่พอใจ)

ยิ่งไปกว่านั้นย้อนกลับไปในสมัยนั้น Microsoft ไม่ได้เอนเอียงไปที่การเป็นมิตรกับโครงการโอเพ่นซอร์สอย่างแน่นอน ไม่ใช่ Linux หรือ GCC อย่างแน่นอน

แล้วทำไมพวกเขาถึงร่วมมือกับ ABI? ฉันเดาว่า ABI แตกต่างกันเพียงเพราะได้รับการออกแบบในเวลาเดียวกันไม่มากก็น้อยและแยกจากกัน

คำพูดอื่นจาก "A History of Modern 64-bit Computing":

ควบคู่ไปกับการทำงานร่วมกันของ Microsoft AMD ยังมีส่วนร่วมกับชุมชนโอเพ่นซอร์สเพื่อเตรียมความพร้อมสำหรับชิป AMD ทำสัญญากับทั้ง Code Sorcery และ SuSE สำหรับการทำงานของห่วงโซ่เครื่องมือ (Red Hat มีส่วนร่วมกับ Intel บนพอร์ต IA64 tool chain แล้ว) รัสเซลอธิบายว่า SuSE ผลิตคอมไพเลอร์ C และ FORTRAN และ Code Sorcery ได้ผลิตคอมไพเลอร์ Pascal เวเบอร์อธิบายว่า บริษัท ยังทำงานร่วมกับชุมชน Linux เพื่อเตรียมพอร์ต Linux ความพยายามนี้มีความสำคัญมาก: เป็นแรงจูงใจให้ Microsoft ยังคงลงทุนในความพยายามของ Windows AMD64 และยังทำให้มั่นใจได้ว่า Linux ซึ่งกำลังกลายเป็นระบบปฏิบัติการที่สำคัญในเวลานั้นจะพร้อมใช้งานเมื่อชิปถูกปล่อยออกมา

Weber กล่าวได้ว่างาน Linux มีความสำคัญอย่างยิ่งต่อความสำเร็จของ AMD64 เนื่องจากทำให้ AMD สามารถผลิตระบบ end-to-end ได้โดยไม่ต้องอาศัยความช่วยเหลือจาก บริษัท อื่น ๆ หากจำเป็น ความเป็นไปได้นี้ทำให้มั่นใจได้ว่า AMD มีกลยุทธ์การอยู่รอดในกรณีที่เลวร้ายที่สุดแม้ว่าพันธมิตรรายอื่น ๆ จะถอยออกมาก็ตามซึ่งจะทำให้พันธมิตรรายอื่นมีส่วนร่วมเพราะกลัวว่าจะถูกทิ้ง

สิ่งนี้บ่งชี้ว่าแม้ AMD จะไม่รู้สึกว่าความร่วมมือเป็นสิ่งที่สำคัญที่สุดระหว่าง MS และ Unix แต่การรองรับ Unix / Linux นั้นสำคัญมาก บางทีแม้แต่การพยายามโน้มน้าวให้ฝ่ายใดฝ่ายหนึ่งหรือทั้งสองฝ่ายประนีประนอมหรือร่วมมือกันก็ไม่คุ้มกับความพยายามหรือความเสี่ยง (?) ในการทำให้ทั้งสองฝ่ายระคายเคือง? บางที AMD อาจคิดว่าการแนะนำ ABI ทั่วไปอาจทำให้ล่าช้าหรือทำให้เป้าหมายที่สำคัญกว่านั้นคือการสนับสนุนซอฟต์แวร์ให้พร้อมเมื่อชิปพร้อม

การคาดเดาในส่วนของฉัน แต่ฉันคิดว่าเหตุผลหลักที่ ABI แตกต่างกันคือเหตุผลทางการเมืองที่ MS และ Unix / Linux ไม่สามารถทำงานร่วมกันได้และ AMD ไม่เห็นว่าเป็นปัญหา


มุมมองที่ดีเกี่ยวกับการเมือง ฉันยอมรับว่าไม่ใช่ความผิดหรือความรับผิดชอบของ AMD ฉันตำหนิ Microsoft ที่เลือกรูปแบบการโทรที่แย่กว่านี้ ถ้ารูปแบบการโทรของพวกเขาดีขึ้นฉันก็มีความเห็นอกเห็นใจบ้าง แต่พวกเขาต้องเปลี่ยนจาก ABI เริ่มต้นเป็น__vectorcallเพราะการส่ง__m128ต่อสแต็กถูกดูด การมีความหมายที่สงวนไว้สำหรับการโทรที่ 128b ต่ำของเวกเตอร์ regs บางตัวก็แปลกเช่นกัน (ความผิดส่วนหนึ่งของ Intel ที่ไม่ได้ออกแบบกลไกบันทึก / กู้คืนที่ขยายได้ด้วย SSE แต่เดิมและยังไม่ใช้ AVX)
Peter Cordes

1
ฉันไม่มีความเชี่ยวชาญหรือความรู้เลยว่าABI ดีแค่ไหน บางครั้งฉันจำเป็นต้องรู้ว่ามันคืออะไรเพื่อที่ฉันจะได้เข้าใจ / ดีบักในระดับแอสเซมบลี
Michael Burr

1
ABI ที่ดีจะลดขนาดโค้ดและจำนวนคำสั่งและช่วยให้การอ้างอิงต่ำเวลาแฝงต่ำโดยหลีกเลี่ยงการเดินทางผ่านหน่วยความจำเพิ่มเติม (สำหรับ args หรือสำหรับคนในพื้นที่ที่ต้องทำหก / โหลดใหม่) มีการแลกเปลี่ยน โซนสีแดงของ SysV ใช้คำแนะนำเพิ่มเติมสองสามคำในที่เดียว (ตัวจัดการตัวจัดการสัญญาณของเคอร์เนล) เพื่อประโยชน์ที่ค่อนข้างใหญ่สำหรับฟังก์ชันใบไม้ที่ไม่ต้องปรับตัวชี้สแต็กเพื่อให้ได้พื้นที่รอยขีดข่วน นั่นคือชัยชนะที่ชัดเจนโดยมีข้อเสียเกือบเป็นศูนย์ มันถูกนำมาใช้โดยไม่มีการอภิปรายหลังจากที่เสนอให้ SysV
Peter Cordes

1
@dgnuff: ใช่แล้วนั่นคือคำตอบของเหตุใดรหัสเคอร์เนลจึงใช้ Red Zoneไม่ได้ การขัดจังหวะใช้สแต็กเคอร์เนลไม่ใช่สแต็กพื้นที่ผู้ใช้แม้ว่าจะมาถึงเมื่อ CPU กำลังเรียกใช้รหัสพื้นที่ผู้ใช้ เคอร์เนลไม่เชื่อถือสแต็กพื้นที่ผู้ใช้เนื่องจากเธรดอื่นในกระบวนการพื้นที่ผู้ใช้เดียวกันสามารถแก้ไขได้ดังนั้นจึงเข้าควบคุมเคอร์เนล!
Peter Cordes

1
@ DavidA.Gray: ใช่ ABI ไม่ได้บอกว่าคุณต้องใช้ RBP เป็นตัวชี้เฟรมดังนั้นโค้ดที่ปรับให้เหมาะสมมักจะไม่ (ยกเว้นในฟังก์ชันที่ใช้allocaหรือกรณีอื่น ๆ ) นี่เป็นเรื่องปกติหากคุณคุ้นเคยกับgcc -fomit-frame-pointerการเป็นค่าเริ่มต้นบน Linux ABI กำหนดเมทาดาทาสแต็กคลายตัวที่อนุญาตให้การจัดการข้อยกเว้นยังคงทำงานได้ (ฉันคิดว่ามันใช้งานได้เช่น GNU / Linux x86-64 เนื้อหา CFI ของ System V .eh_frame) gcc -fomit-frame-pointerเป็นค่าเริ่มต้น (พร้อมการเปิดใช้งานการเพิ่มประสิทธิภาพ) ตั้งแต่ตลอดไปบน x86-64 และคอมไพเลอร์อื่น ๆ (เช่น MSVC) ก็ทำสิ่งเดียวกัน
Peter Cordes

12

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

ฉันไม่สามารถบอกคุณได้ว่าทำไมถึงเปลี่ยน RCX และ RDX


1
รูปแบบการโทรทั้งหมดมีการลงทะเบียนบางรายการที่กำหนดให้เป็นรอยขีดข่วนและบางส่วนจะเก็บรักษาไว้เช่น ESI / EDI และ RSI / RDI บน Win64 แต่สิ่งเหล่านี้เป็นการลงทะเบียนสำหรับวัตถุประสงค์ทั่วไป Microsoft สามารถเลือกได้โดยไม่มีปัญหาในการใช้งานที่แตกต่างกัน
JanKanis

1
@Somejan: แน่นอนว่าถ้าพวกเขาต้องการเขียน API ใหม่ทั้งหมดและมี OS สองระบบที่แตกต่างกัน ฉันจะไม่เรียกสิ่งนั้นว่า "ไม่มีปัญหา" เป็นเวลาหลายสิบปีที่ผ่านมา MS ได้ให้คำมั่นสัญญาบางอย่างเกี่ยวกับสิ่งที่จะทำและจะไม่ทำกับการลงทะเบียน x86 และพวกเขามีความสอดคล้องและเข้ากันได้มากหรือน้อยตลอดเวลา พวกเขาจะไม่โยนสิ่งนั้นทั้งหมดออกไปนอกหน้าต่างเพียงเพราะคำสั่งบางอย่างจาก AMD โดยเฉพาะอย่างยิ่งโดยพลการและอยู่นอกขอบเขตของการ "สร้างโปรเซสเซอร์"
cHao

5
@Somejan: AMD64 UN * X ABI เป็นแบบนั้นเสมอ - เป็นชิ้นส่วนเฉพาะของ UNIX เอกสารx86-64.org/documentation/abi.pdfมีชื่อว่าSystem V Application Binary Interface, AMD64 Architecture Processor Supplementด้วยเหตุผล UNIX ABI (ทั่วไป) (คอลเลกชันแบบหลายไดรฟ์ข้อมูลsco.com/developers/devspecs ) ออกจากส่วนสำหรับโปรเซสเซอร์เฉพาะบทที่ 3 - ส่วนเสริม - ซึ่งเป็นรูปแบบการเรียกใช้ฟังก์ชันและกฎโครงร่างข้อมูลสำหรับโปรเซสเซอร์เฉพาะ
แฟรงค์

7
@Somejan: Microsoft Windows ไม่เคยพยายามใกล้ชิดกับ UN * X เป็นพิเศษและเมื่อพูดถึงการพอร์ต Windows ไปที่ x64 / AMD64 พวกเขาก็เลือกที่จะขยายรูปแบบการโทรของตัวเอง __fastcallคุณอ้าง Win32 / Win64 เข้ากันไม่ได้ แต่แล้วมองอย่างใกล้ชิด: สำหรับฟังก์ชั่นที่ใช้สอง 32bit args และผลตอบแทน 32bit, Win64 และ Win32 __fastcallจริงเป็น 100% เข้ากันได้ (Regs เดียวกันสำหรับการส่งผ่านสอง 32bit args ค่าส่งกลับเดียวกัน) แม้แต่รหัสไบนารี (!) บางตัวก็อาจทำงานได้ทั้งสองโหมดการทำงาน ด้าน UNIX แตกสลายด้วย "วิธีเก่า ๆ " โดยสิ้นเชิง ด้วยเหตุผลที่ดี แต่การหยุดพักก็คือการหยุดพัก
แฟรงค์

2
@Olof: มันเป็นมากกว่าแค่คอมไพเลอร์ ฉันมีปัญหากับ ESI และ EDI เมื่อฉันทำสิ่งต่างๆแบบสแตนด์อโลนใน NASM Windows ให้ความสำคัญกับการลงทะเบียนเหล่านั้นอย่างแน่นอน แต่ใช่คุณสามารถใช้ได้หากคุณบันทึกไว้ก่อนที่จะทำและกู้คืนก่อนที่ Windows จะต้องการ
cHao
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.