นักแปลคอมไพเลอร์จำเป็นต้องเข้าใจรหัสเครื่องจริงหรือไม่? [ปิด]


10

อาจเป็นคำถามแปลก ๆ

ผู้ชายกำลังเขียนคอมไพเลอร์ C ++ (หรือภาษาที่ไม่ใช่ VM): เขาจำเป็นต้องสามารถอ่าน / เขียนภาษาเครื่องดิบได้หรือไม่? มันทำงานอย่างไร

แก้ไข: ฉันหมายถึงเฉพาะผู้แปลที่รวบรวมรหัสเครื่องไม่ใช่ภาษาการเขียนโปรแกรมอื่น



1
ไม่คุณไม่จำเป็นต้องรู้ด้วยซ้ำคุณสามารถคัดลอกข้อมูลจำเพาะ ISA เป้าหมายของคุณได้อย่างสุ่มสี่สุ่มห้า: dl.acm.org/citation.cfm?id=1706346
SK-logic

1
Coffescript รวบรวมไปยังจาวาสคริปต์
Kartik

@Kartik คอมไพเลอร์ CoffeeScript ที่คอมไพล์ไปยัง Javascript หรือไม่รวมถึง Javascript คอมไพเลอร์ที่คอมไพล์กับ Javascript ที่คอมไพล์ด้วยหรือไม่? หรือมันจะรวบรวมเฉพาะซอร์สโค้ด Javascript และไม่มีอะไรเพิ่มเติม?
Aviv Cohn

คอมไพเลอร์ coffeescript เพียงแปลง cofeescript เป็น javascript Javascript ไม่ได้ถูกรวบรวม แต่จัดการโดยเบราว์เซอร์ ฉันอยากจะบอกว่าคุณสามารถเขียนคอมไพเลอร์ที่รวบรวมภาษาหนึ่งเป็นอีกภาษาหนึ่งคุณไม่จำเป็นต้องรู้ภาษาเครื่องสำหรับสิ่งนั้น อีกตัวอย่างหนึ่งคือคอมไพเลอร์ 'SPL' ที่คอมไพล์ด้วยเช็คสเปียร์เล่นกับ C ++ shakespearelang.sourceforge.net
Kartik

คำตอบ:


15

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

วิธีการแยกความแตกต่างของการใช้งานที่ไม่ใช่ VM และการใช้งาน VM ไม่เป็นประโยชน์

  • สำหรับผู้เริ่มต้นการใช้ VM หรือการคอมไพล์ล่วงหน้ากับรหัสเครื่องเป็นวิธีที่แตกต่างกันในการใช้ภาษา ในกรณีส่วนใหญ่ภาษาสามารถนำมาใช้โดยใช้กลยุทธ์ใดกลยุทธ์หนึ่ง จริง ๆ แล้วฉันต้องใช้ล่าม C ++ ครั้งเดียว

  • นอกจากนี้ VMs จำนวนมากเช่น JVM ทั้งคู่มีรหัสเครื่องไบนารีและแอสเซมเบลอร์บางตัวเหมือนกับสถาปัตยกรรมทั่วไป

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

สิ่งที่ดีเกี่ยวกับ LLVM คือ VM ของมันเป็นเพียงนามธรรมและรหัสไบต์มักจะไม่ถูกตีความ แต่ JITted โปร่งใสแทน ดังนั้นจึงเป็นไปได้ทั้งหมดที่จะเขียนภาษาที่เรียบเรียงอย่างมีประสิทธิภาพโดยไม่ต้องรู้เกี่ยวกับชุดคำสั่งของ CPU


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

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

5
@Prog ใช่ หากคุณสร้างเลเยอร์ของสิ่งที่เป็นนามธรรมคุณจะต้องเข้าใจเลเยอร์ที่อยู่ด้านล่างของคุณ แม้ว่าจะมีประโยชน์ในการมีความเข้าใจพื้นฐานของเลเยอร์ทั้งหมด แต่ก็ไม่จำเป็นจริงๆ คุณไม่จำเป็นต้องเข้าใจควอนตัมฟิสิกส์เพื่อใช้ทรานซิสเตอร์ คุณไม่จำเป็นต้องเข้าใจการออกแบบชิปเพื่อใช้งาน CPU คุณไม่จำเป็นต้องรู้รหัสเครื่องเพื่อเขียนชุดประกอบ คุณไม่จำเป็นต้องรู้ชุดคำสั่งของแพลตฟอร์มเมื่อใช้ VM ฯลฯ แต่มีบางคนต้องสร้างระดับนามธรรมที่ต่ำกว่าของคุณ
amon

1
@ SK-logic ไม่จริง (อย่างน้อยถ้าคุณต้องการรหัสที่ดี) จากสิ่งที่ฉันเคยได้ยิน คนที่ใช้แบ็กเอนด์ Aarch64 สำหรับ llvm นั้นมีความท้าทายอยู่บ้าง และที่ละเลยช้างที่ใหญ่ที่สุดในห้องพัก: รูปแบบหน่วยความจำของ ISA และหน่วยความจำแบบของภาษาที่คุณอยู่ในความสนใจคุณสามารถทำงานกับคอมไพเลอร์ แต่คุณไม่สามารถทำงานในแบ็กเอนด์โดยไม่เข้าใจสถาปัตยกรรม .. .
Voo

1
ฉันจะเพิ่มว่าไม่มีความแตกต่างอย่างมากระหว่างชุดประกอบและรหัสเครื่องแนวคิด คุณจะไม่ได้รับประโยชน์มากนักเมื่อรู้วิธีใช้คำสั่งเฉพาะ opcode ของคำสั่งนั้นคืออะไร ถ้าคุณรู้วิธีใช้ MOV มันไม่สำคัญเลยถ้าคุณไม่รู้ว่ามันคือคำสั่ง 27 ซึ่งฉันคิดว่าคล้ายกับที่ @ SK-logic อธิบายไว้
whatsisname

9

ไม่จุดสำคัญของคำถามของคุณคือการรวบรวมเป็นคำที่กว้างมาก การรวบรวมสามารถเกิดขึ้นได้จากภาษาใด ๆ กับภาษาใด ๆ และแอสเซมบลี / รหัสเครื่องเป็นเพียงหนึ่งในหลายภาษาสำหรับเป้าหมายการรวบรวม ตัวอย่างเช่นภาษา Java และ. NET เช่น C #, F # และ VB.NET ทั้งหมดรวบรวมรหัสกลางบางชนิดแทนรหัสเฉพาะเครื่อง ไม่สำคัญว่าจะทำงานบน VM หรือไม่ภาษาก็ยังคงถูกคอมไพล์ นอกจากนี้ยังมีตัวเลือกในการรวบรวมภาษาอื่นเช่น C. C เป็นเป้าหมายการรวบรวมที่เป็นที่นิยมมากและมีเครื่องมือมากมายที่ทำได้ และในที่สุดคุณสามารถใช้เครื่องมือหรือไลบรารีเพื่อทำงานอย่างหนักในการสร้างรหัสเครื่องให้คุณ ตัวอย่างเช่นLLVMซึ่งสามารถลดความพยายามในการสร้างคอมไพเลอร์แบบสแตนด์อโลน

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


และบุคคลที่เขียนเครื่องมือหรือไลบรารีที่ทำการแปลงจริงเป็นภาษาเครื่องจำเป็นต้องเข้าใจภาษาเครื่องโดยสมบูรณ์ใช่ไหม
Aviv Cohn

3
@Prog คุณจำเป็นต้องเข้าใจภาษาการเขียนโปรแกรมเพื่อที่จะตั้งโปรแกรมหรือไม่? ไม่ แต่คุณอาจเขียนโค้ดย่อยที่ดีที่สุดและคุณไม่สามารถทำสิ่งต่าง ๆ ที่คนอื่นสามารถทำได้ คุณจำเป็นต้องเข้าใจภาษาเครื่องโดยสมบูรณ์หรือไม่หากคุณเขียนคอมไพเลอร์ที่แปลเป็นภาษานั้น ไม่ แต่คอมไพเลอร์ของคุณจะไม่ดีพอและไม่สามารถทำบางสิ่งได้
Sumurai8 8

@ Sumurai8: คุณสามารถ "เข้าใจ" ภาษาเครื่องได้บ้างในระดับหนึ่งเพื่อที่จะเขียนอิมิตเตอร์ของเครื่องที่เข้าใจสิ่งต่าง ๆ ได้ดีกว่าที่คุณทำ ตัวอย่างเช่นถ้าคุณเขียนเฟรมเวิร์กที่ดีคุณอาจกำหนดค่านิยามของ opcode แต่ละตัวพร้อมกับข้อควรพิจารณาด้านราคาและการวางท่อจากนั้นเฟรมเวิร์กของคุณสามารถเขียนรหัสเครื่องที่ปรับให้เหมาะสมได้แม้ว่าคุณจะไม่มีความชำนาญ ความสามารถในการเขียนโปรแกรมรหัสเครื่องอย่างมีประสิทธิภาพนั้นอาจไม่ทำให้คุณเจ็บ
Steve Jessop

@SteveJessop ถ้าคุณเข้าใจแต่ละ opcode ถึงจุดที่คุณสามารถเรียนรู้วิธีการเชื่อมโยง opcode นั้นร่วมกับ opcode อื่น ๆ เพื่อแสดงแนวคิดระดับที่สูงขึ้นคุณจะเข้าใจภาษาเครื่องอย่างสมบูรณ์ คุณอยู่แล้วเพียงแค่ขี้เกียจเกินไปที่จะหาทางออกที่ดีที่สุดสำหรับทุกปัญหาออกมี ;-)
Sumurai8

@ Sumurai8: อืม แต่อย่างน้อยในหลักการฉันอาจ "เข้าใจ" แต่ละ opcode สั้น ๆ เป็นเวลาห้านาทีมันใช้เวลาฉันในการกำหนดค่าและจากนั้นก็ลืมมันเมื่อฉัน "เข้าใจ" opcode หลังจากนั้น นั่นอาจไม่ใช่สิ่งที่ผู้ถามหมายถึง "สามารถอ่าน / เขียนภาษาเครื่องดิบ" แน่นอนว่าฉันสมมติว่าเป็นเฟรมเวิร์กที่ดีทีเดียวที่นี่มันสามารถกำหนดค่าได้เพียงพอที่จะกำหนดและใช้ข้อมูลที่เป็นประโยชน์ทั้งหมดเกี่ยวกับ opcode ของชุดคำสั่ง LLVM ค่อนข้างมีจุดมุ่งหมายสำหรับเรื่องนี้ แต่ตาม "Voo" (ในความคิดเห็นด้านล่าง) ไม่ได้ตีมัน
Steve Jessop

3

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

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

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


2

นานมาแล้วฉันเขียนคอมไพเลอร์ที่แปลงระหว่างสองเชลล์สคริปต์ที่แตกต่างกัน มันไม่มีทางใกล้กับรหัสเครื่อง

คอมไพเลอร์เขียนต้องเข้าใจผลลัพธ์ของพวกเขาแต่นั่นมักจะไม่ใช่รหัสเครื่อง

โปรแกรมเมอร์ส่วนใหญ่จะไม่เขียนคอมไพเลอร์ที่เอาท์พุทรหัสเครื่องหรือรหัสแอสเซมบลี แต่คอมไพเลอร์แบบกำหนดเองอาจมีประโยชน์มากในโครงการจำนวนมาก

YACC เป็นคอมไพเลอร์ตัวหนึ่งที่ไม่ส่งสัญญาณรหัสเครื่อง….


0

คุณไม่จำเป็นต้องเริ่มต้นด้วยความรู้รายละเอียดของความหมายของอินพุตและเอาต์พุตภาษาของคุณ แต่คุณดีกว่าจบด้วยความรู้ที่มีรายละเอียดอย่างประณีตทั้งสองอย่างมิฉะนั้นคอมไพเลอร์ของคุณ ดังนั้นหากอินพุตของคุณคือ C ++ และเอาต์พุตของคุณเป็นภาษาเครื่องเฉพาะคุณจะต้องรู้ถึงความหมายของทั้งคู่

นี่คือรายละเอียดปลีกย่อยบางส่วนในการคอมไพล์รหัส C ++ กับเครื่อง: (ด้านบนสุดของหัวของฉันฉันแน่ใจว่ามีอีกมากที่ฉันลืม)

  1. จะมีขนาดเท่าintไหร่ ตัวเลือก "ถูกต้อง" ที่นี่เป็นศิลปะตามขนาดตัวชี้ธรรมชาติของเครื่องประสิทธิภาพของ ALU สำหรับการดำเนินการทางคณิตศาสตร์ในขนาดต่างๆและตัวเลือกที่ทำโดยคอมไพเลอร์ที่มีอยู่สำหรับเครื่อง เครื่องมีเลขคณิต 64 บิตหรือไม่? หากไม่ใช่จากนั้นการเพิ่มจำนวนเต็มแบบ 32 บิตควรแปลเป็นคำสั่งในขณะที่การเพิ่มจำนวนเต็มแบบ 64 บิตควรแปลเป็นการเรียกใช้ฟังก์ชันเพื่อทำการเพิ่มแบบ 64 บิต เครื่องมีการเพิ่มแบบ 8 บิตและ 16 บิตหรือไม่หรือคุณต้องจำลองการทำงานด้วย ops และการปิดบังแบบ 32 บิต (เช่น DEC Alpha 21064) หรือไม่?

  2. ระเบียบการเรียกที่ใช้โดยคอมไพเลอร์ห้องสมุดและภาษาอื่น ๆ บนเครื่องคืออะไร? พารามิเตอร์ถูกส่งไปบนสแต็กจากขวาไปซ้ายหรือจากซ้ายไปขวาหรือไม่? ทำพารามิเตอร์บางอย่างไปในการลงทะเบียนในขณะที่คนอื่นไปในกอง? ints และลอยในช่องว่างการลงทะเบียนที่แตกต่างกัน? พารามิเตอร์การจัดสรรรีจิสเตอร์จำเป็นต้องได้รับการดูแลเป็นพิเศษจากการโทรแบบ varargs หรือไม่? รีจิสเตอร์ใดบ้างที่ถูกบันทึกไว้สำหรับการโทร คุณสามารถเพิ่มประสิทธิภาพการโทรออกได้หรือไม่?

  3. คำแนะนำการเลื่อนของแต่ละเครื่องทำอะไร? หากคุณขอให้เปลี่ยนจำนวนเต็ม 64 บิตเป็น 65 บิตผลลัพธ์คืออะไร (ในหลาย ๆ เครื่องผลลัพธ์จะเหมือนกับการขยับ 1 บิตส่วนอื่น ๆ ผลลัพธ์จะเป็น "0")

  4. ซีแมนทิกส์ความสอดคล้องของหน่วยความจำคืออะไร? C ++ 11 มีซีแมนทิกส์ของหน่วยความจำที่กำหนดไว้เป็นอย่างดีซึ่งวางข้อ จำกัด ในการปรับให้เหมาะสมบางอย่างในบางกรณี แต่อนุญาตการปรับให้เหมาะสมในกรณีอื่น ๆ หากคุณกำลังรวบรวมภาษาที่ไม่ได้มีการกำหนดไว้อย่างดีความหมายของหน่วยความจำ (เช่นรุ่น C / C ++ ก่อน C ++ 11 และอีกหลายภาษาที่จำเป็นอื่น ๆ ทุกครั้ง) แล้วคุณจะมีการคิดค้นความหมายของหน่วยความจำที่คุณไปพร้อมและมักจะ คุณจะต้องคิดค้นซีแมนทิกส์ของหน่วยความจำที่ตรงกับซีแมนติกส์ของเครื่องมากที่สุด

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