รหัสเครื่อง

จากวิกิพีเดีย สารานุกรมเสรี
(เปลี่ยนทางจาก ภาษาเครื่อง)
จอภาพแสดงรหัสเครื่องในคอมพิวเตอร์บอร์ดเดี่ยว W65C816S แสดงการทำย้อนกลับเป็นรหัสแอสเซมบลี พร้อมด้วยเรจิสเตอร์ของหน่วยประมวลผล และข้อมูลเทออกจากหน่วยความจำ

รหัสเครื่อง หรือ ภาษาเครื่อง คือกลุ่มของคำสั่งเครื่องที่กระทำการโดยตรงโดยหน่วยประมวลผลกลาง (CPU) ของคอมพิวเตอร์ คำสั่งเครื่องแต่ละคำสั่งจะปฏิบัติงานเฉพาะกิจงานเดียวเท่านั้น เช่นการบรรจุ (load) การกระโดด (jump) หรือการดำเนินการผ่านหน่วยคำนวณและตรรกะ (ALU) บนหน่วยของข้อมูลในหน่วยความจำหรือเรจิสเตอร์ ทุก ๆ โปรแกรมที่กระทำการโดยหน่วยประมวลผลกลางสร้างขึ้นจากอนุกรมของคำสั่งเครื่องเช่นว่านั้น

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

ปัจจุบันนี้โปรแกรมเกือบทั้งหมดในทางปฏิบัติเขียนขึ้นด้วยภาษาแอสเซมบลีหรือภาษาระดับสูงกว่า แล้วแปลเป็นรหัสเครื่องที่กระทำการได้โดยคอมไพเลอร์และ/หรือแอสเซมเบลอร์ กับลิงเกอร์ อย่างไรก็ดี โปรแกรมที่เขียนด้วยภาษาที่แปลด้วยอินเทอร์พรีเตอร์[1]จะไม่ถูกแปลเป็นรหัสเครื่อง ถึงแม้ว่าอินเทอร์พรีเตอร์ (ซึ่งอาจเห็นเป็นชื่อ ตัวกระทำการ หรือ ตัวประมวลผล) โดยทั่วไปประกอบขึ้นจากรหัสเครื่องที่กระทำการได้โดยตรง

คำสั่งเครื่องที่เป็นรหัสเครื่อง[แก้]

ดูบทความหลักที่: ชุดของคำสั่งเครื่อง

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

รหัสของชุดของคำสั่งเครื่องอาจมีความยาวเท่ากันหมดทุกคำสั่งหรือมีความยาวแปรผันก็ได้ วิธีการจัดการแบบรูปของรหัสเครื่องขึ้นอยู่กับสถาปัตยกรรมนั้น ๆ เป็นอย่างยิ่ง และมักจะขึ้นอยู่กับชนิดของคำสั่ง คำสั่งเครื่องส่วนมากมีฟีลด์ออปโคด (opcode) หนึ่งฟีลด์หรือมากกว่าซึ่งใช้ระบุชนิดของคำสั่งพื้นฐาน (เช่นเลขคณิต ตรรกศาสตร์ การกระโดด ฯลฯ) และการดำเนินการแท้จริง (เช่นการบวก การเปรียบเทียบ) และมีฟีลด์อื่น ๆ ที่อาจใช้สำหรับระบุชนิดของตัวถูกดำเนินการ (operand) ภาวะการกำหนดตำแหน่งที่อยู่ (addressing mode) ออฟเซตของตำแหน่งที่อยู่หรือดัชนี หรือค่าแท้จริงโดยตัวมันเอง (ตัวถูกดำเนินการที่เป็นค่าคงตัวที่บรรจุอยู่ในคำสั่งเครื่องเช่นนั้นเรียกว่า ค่าใช้ทันที, immediate)[2]

ไม่ใช่ว่าทุกเครื่องหรือทุกคำสั่งจะมีตัวถูกดำเนินการชัดแจ้ง เครื่องที่ใช้ตัวสะสม (accumulator machine) มีตัวถูกดำเนินการข้างซ้ายแบบผสม และคืนค่าผลลัพธ์ในตัวสะสม (accumulator) ปริยาย สำหรับคำสั่งเลขคณิตส่วนใหญ่ สถาปัตยกรรมอื่น (เช่น 8086 และตระกูล x86) มีคำสั่งธรรมดาในรุ่นของตัวสะสมอยู่ด้วย ซึ่งคำสั่งที่ยาวกว่าจะทำเรจิสเตอร์อันหนึ่งในเรจิสเตอร์ทั่วไปเป็นตัวสะสม เครื่องที่ใช้กองซ้อน (stack machine) มีตัวถูกดำเนินการส่วนใหญ่หรือทั้งหมดอยู่บนกองซ้อนปริยาย คำสั่งเครื่องที่มีจุดประสงค์พิเศษก็มักจะขาดตัวถูกดำเนินการชัดแจ้ง (ตัวอย่างเช่น ซีพียูไอดีในสถาปัตยกรรม x86 เขียนค่าต่าง ๆ ลงในเรจิสเตอร์ปลายทางเป็นปริยาย 4 เรจิสเตอร์) ความแตกต่างระหว่างตัวถูกดำเนินการชัดแจ้งกับปริยายเช่นนี้สำคัญต่อโปรแกรมสร้างรหัสเครื่อง โดยเฉพาะอย่างยิ่งในเรื่องการจัดสรรเรจิสเตอร์และส่วนติดตามพิสัยแบบสด โปรแกรมทำรหัสให้เหมาะที่สุด (code optimizer) ที่ดีสามารถติดตามตัวถูกดำเนินการทั้งชัดแจ้งและปริยาย ซึ่งอาจช่วยให้เกิดการแพร่กระจายค่าคงตัว (constant propagation) ได้บ่อยยิ่งขึ้น การพับทบค่าคงตัว (constant folding) ของเรจิสเตอร์ (เรจิสเตอร์ที่กำหนดให้เป็นผลลัพธ์จากนิพจน์ของค่าคงตัวจะถูกแทนที่ด้วยค่าคงตัวนั้น) และการปรับปรุงรหัสอื่น ๆ ให้ดีขึ้น

โปรแกรม[แก้]

โปรแกรมคอมพิวเตอร์คือลำดับของคำสั่งเครื่องที่กระทำการโดยหน่วยประมวลผลกลาง ขณะที่หน่วยประมวลผลอย่างง่ายกระทำการคำสั่งเครื่องทีละคำสั่ง แต่หน่วยประมวลผลซูเปอร์สเกลาร์ (superscalar) สามารถกระทำการคำสั่งเครื่องได้พร้อม ๆ กันทีละหลายคำสั่ง

การไหลของโปรแกรม (program flow) อาจได้รับอิทธิพลจากคำสั่ง "กระโดด" แบบพิเศษที่ถ่ายโอนการกระทำการไปยังคำสั่งอื่น แทนที่จะเป็นคำสั่งถัดไปตามลำดับเลข การกระโดดแบบมีเงื่อนไขจะเกิดขึ้น (การกระทำการดำเนินต่อที่ตำแหน่งอื่น) หรือไม่เกิดขึ้นก็ได้ (การกระทำดำเนินต่อไปยังคำสั่งถัดไป) โดยขึ้นอยู่กับเงื่อนไขที่กำหนด

ภาษาแอสเซมบลี[แก้]

ดูบทความหลักที่: ภาษาแอสเซมบลี

การถอดความรหัสเครื่องที่สามารถอ่านได้ง่ายขึ้นอย่างมากอย่างหนึ่งคือภาษาแอสเซมบลี ซึ่งเป็นภาษาที่ใช้รหัสช่วยจำ (mnemonic code) อ้างถึงรหัสของคำสั่งเครื่อง แทนที่จะใช้ค่าตัวเลขของคำสั่งเครื่องโดยตรง ตัวอย่างเช่น หน่วยประมวลผล ซิล็อก แซด80 (Zilog Z80) รหัสเครื่อง 00000101 คือคำสั่งที่ทำให้หน่วยประมวลผลกลางลดค่าเรจิสเตอร์ B ลงหนึ่ง จะเขียนแทนด้วยภาษาแอสเซมบลีว่า DEC B เป็นต้น

ตัวอย่าง[แก้]

สถาปัตยกรรมมิปส์ (MIPS architecture) ได้ให้ตัวอย่างรหัสเครื่องไว้ ซึ่งคำสั่งเครื่องของมันจะมีขนาด 32 บิตเสมอ ชนิดของคำสั่งกำหนดด้วยฟีลด์ op (การดำเนินการ) คือบิตบนสุด 6 บิต คำสั่งชนิด J (กระโดด) และชนิด I (ค่าใช้ทันที) จะระบุไว้อย่างชัดเจนด้วย op ส่วนคำสั่งชนิด R (เรจิสเตอร์) ต้องมีฟีลด์ funct (ฟังก์ชัน) เพิ่มขึ้นมาเพื่อเจาะจงการดำเนินการที่แน่นอน ฟีลด์ที่ใช้ในคำสั่งสามชนิดมีดังนี้

   6      5     5     5     5      6 บิต
[  op  |  rs |  rt |  rd |shamt| funct]  ชนิด R
[  op  |  rs |  rt | address/immediate]  ชนิด I
[  op  |        target address        ]  ชนิด J

rs, rt, และ rd คือเรจิสเตอร์ที่ถูกดำเนินการ; shamt คือปริมาณการเลื่อน; address หรือ immediate คือค่าที่ถูกดำเนินการโดยตรง

ตัวอย่าง การบวกเรจิสเตอร์ 1 กับเรจิสเตอร์ 2 แล้วเก็บผลลัพธ์ไว้ในเรจิสเตอร์ 6 เขียนได้ดังนี้

[  op  |  rs |  rt |  rd |shamt| funct]
    0     1     2     6     0     32     ฐานสิบ
 000000 00001 00010 00110 00000 100000   ฐานสอง

การบรรจุค่าให้กับเรจิสเตอร์ 8 โดยนำค่ามาจากเซลล์หน่วยความจำที่ 68 ถัดจากตำแหน่งที่ระบุในเรจิสเตอร์ 3 เขียนได้ดังนี้

[  op  |  rs |  rt | address/immediate]
   35     3     8           68           ฐานสิบ
 100011 00011 01000 00000 00001 000100   ฐานสอง

การกระโดดไปที่ตำแหน่ง 1024 เขียนได้ดังนี้

[  op  |        target address        ]
    2                 1024               ฐานสิบ
 000010 00000 00000 00000 10000 000000   ฐานสอง

ความสามารถในการอ่านได้โดยมนุษย์[แก้]

รหัสเครื่องไม่สามารถอ่านได้อย่างยิ่ง ดังเช่นที่สำนักงานลิขสิทธิ์แห่งสหรัฐอเมริกา (United States Copyright Office) ไม่สามารถระบุได้ว่า โปรแกรมที่เข้ารหัสแล้วแต่ละโปรแกรมเป็นผลงานต้นฉบับของผู้ถือลิขสิทธิ์หรือไม่[3] อย่างไรก็ตามสำนักงานลิขสิทธิ์ก็อนุญาตให้จดทะเบียนลิขสิทธิ์ของโปรแกรมคอมพิวเตอร์ได้[4] ดักลาส ฮอฟสตัดเทอร์ (Douglas Hofstadter) ได้เปรียบเทียบรหัสเครื่องกับรหัสพันธุกรรมว่า "การมองดูโปรแกรมที่ถูกเขียนเป็นรหัสเครื่อง ก็เทียบได้อย่างกว้าง ๆ กับการมองดูโมเลกุลดีเอ็นเอทีละอะตอม"[5]

อ้างอิงและเชิงอรรถ[แก้]

  1. ตัวอย่างเช่น ภาษาเบสิกหลายรุ่น โดยเฉพาะรุ่นแรก ๆ ภาษาสมอลล์ทอล์ก แมตแล็บ ภาษาเพิร์ล ภาษาไพทอน ภาษารูบี และภาษาสคริปต์หรือภาษาอื่นที่มีจุดประสงค์เฉพาะ
  2. Immediate operands
  3. Pamela Samuelson (Sep 1984). CONTU Revisited: The Case against Copyright Protection for Computer Programs in Machine-Readable Form 1984 (4). Duke Law Journal. pp. 663–769. JSTOR 1372418. 
  4. "Copyright Registration for Computer Programs". US Copyright Office. August 2008. สืบค้นเมื่อ February 23, 2014. 
  5. D. Hofstadter (1980). Gödel, Escher, Bach: An Eternal Golden Braid. p. 290.