x86-64 รหัสเครื่อง, 8 ไบต์
แรงบันดาลใจจากคำตอบของBruce Forteแต่อยู่ภายใต้การเล็กน้อย :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
InfiniteLoop:
F3 73 FD rep jnc InfiniteLoop ; test CF; infinite loop back here if input was even
C3 ret ; return with original input in EAX if it was odd
พารามิเตอร์เลขจำนวนเต็มเดี่ยวถูกนำมาใช้ในการEDI
ลงทะเบียนตามการเรียก System V AMD64
สำเนาของค่านี้จะทำในขั้นต้นและใส่ลงในEAX
เพื่อที่จะสามารถกลับมาตามความเหมาะสม ( LEA
ใช้แทนปกติMOV
เพราะเราต้องการคำสั่งที่มีไบต์คี่)
จากนั้นค่าในEDI
จะถูกเลื่อนไปทางขวา 1 ซึ่งวางบิต shifted-off ลงใน carry flag (CF) บิตนี้จะเป็น 0 ถ้าตัวเลขเป็นเลขคู่หรือ 1 ถ้าเป็นเลขคี่
จากนั้นเราจะทดสอบ CF โดยใช้JNC
คำสั่งซึ่งจะแตกสาขาเฉพาะถ้า CF เป็น 0 (เช่นจำนวนนั้นเท่ากัน) นี่หมายความว่าเราจะเข้าสู่วงวนไม่สิ้นสุดสำหรับค่าที่เท่ากัน สำหรับค่าคี่เราจะผ่านและส่งคืนค่าดั้งเดิม ( EAX
เป็น)
มีเคล็ดลับเล็กน้อยในการJNC
เรียนการสอน - มีREP
คำนำหน้า! โดยปกติแล้วREP
คำนำหน้าจะใช้กับคำสั่งแบบสตริงเท่านั้น แต่เนื่องจากคู่มือ Intel และ AMD ทั้งคู่ยอมรับว่าREP
คำนำหน้าไม่เกี่ยวข้อง / ฟุ่มเฟือย / ซ้ำซ้อนจะถูกละเว้นเราจึงให้คำแนะนำสาขาที่นี่เพื่อทำให้มีความยาว 3 ไบต์ ด้วยวิธีนี้การชดเชยแบบสัมพัทธ์ที่ได้รับการเข้ารหัสในคำสั่งการกระโดดนั้นก็แปลก (และแน่นอนว่าREP
ตัวเองเป็นคำนำหน้าคี่ไบต์)
ขอบคุณพระเจ้าที่RET
ถูกเข้ารหัสโดยใช้ไบต์คี่!
ลองออนไลน์!
ในกรณีที่คุณไม่คิดว่าจะคืนค่าถ้ามันเป็นเลขคี่หรือไปในวงวนไม่สิ้นสุดถ้ามันเป็นเลขคู่ (เพื่อที่คุณจะไม่กลับมา) ตรงตามข้อกำหนด "เอาท์พุท" ของความท้าทายหรือคุณต้องการบางสิ่งที่น่าสนใจมากขึ้น ที่ส่งออกค่าไปยังพอร์ตอนุกรม (แต่ถ้ามันแปลกแน่นอน)
x86-64 รหัสเครื่อง (เอาต์พุตไปยังพอร์ตอนุกรม), 17 ไบต์
8D 07 lea eax, [rdi] ; put copy of input parameter (EDI) in EAX
B1 F7 mov cl, 0xf7 ; put 0xF7 into low-order bits of CX
B5 03 mov ch, 0x03 ; put 0x03 into high-order bits of CX
FE C1 inc cl ; increment low-order bits of CX to 0xF8 (so all together it's now 0x3F8)
0F B7 D1 movzx edx, cx ; move CX to DX ("MOV DX, CX" would have a 16-bit prefix of 0x66)
D1 EF shr edi, 1 ; shift LSB of input parameter into CF
73 01 jnc IsEven ; test CF: branch if 0 (even), fall through if 1 (odd)
EF out dx, eax ; output EAX (original input) to I/O port 0x3F8 (in DX)
IsEven:
C3 ret ; return
สิ่งที่ทำให้สิ่งนี้น่าสนใจยิ่งขึ้นคือโค้ดทำงานได้มากกว่าซึ่งหมายความว่าเป็นการยากที่จะทำทุกอย่างโดยใช้คำสั่งที่เข้ารหัสโดยใช้ไบต์คี่เท่านั้น แน่นอนนี่ก็หมายความว่ามันล้มเหลวที่ code golf ดังนั้นมันเป็นการแลกเปลี่ยนที่น่าสนใจ - คุณต้องการที่น่าสนใจและท้าทายหรือคุณต้องการสั้นไหม?
อย่างไรก็ตามสิ่งนี้ใช้OUT
คำสั่ง x86 เพื่อเขียนไปยังพอร์ต I / O 0x3F8 ซึ่งเป็นพอร์ตอนุกรม COM1 มาตรฐานบนพีซี แน่นอนว่าส่วนที่สนุกสนานคือพอร์ต I / O มาตรฐานทั้งหมด (อนุกรมและขนาน) มีที่อยู่คู่ดังนั้นพวกเขาจึงไม่สามารถเข้ารหัสเป็นOUT
คำสั่งได้ทันทีหรือย้ายไปลงทะเบียนโดยตรง คุณต้องเริ่มต้นด้วยค่าที่น้อยกว่าค่าจริงจากนั้นเพิ่มค่าในการลงทะเบียน นอกจากนี้คุณยัง จำกัด การใช้การลงทะเบียนบางอย่างสำหรับการจัดการเนื่องจากคุณต้องลงทะเบียนที่เข้ารหัสโดยใช้ไบต์คี่ในการเรียนการสอนเมื่อใช้เป็นตัวถูกดำเนินการ
นอกจากนี้ฉันต้องเริ่มต้นการDX
ลงทะเบียน (ผ่านการCX
ลงทะเบียน) ที่ด้านบนของลูปแม้ว่าจะต้องใช้เฉพาะในกรณีที่ค่าเป็นเลขคี่เพื่อให้แน่ใจว่าJNC
คำสั่งนั้นจะมีออฟเซ็ตคี่ อย่างไรก็ตามเนื่องจากสิ่งที่เรากำลังข้ามไปคือOUT
คำแนะนำรหัสทั้งหมดนี้คือวงจรการเสียและการลงทะเบียนขูดขีด มันไม่ได้ส่งออกอะไรเลยดังนั้นจึงไม่ผิดกฎ
สุดท้ายฟังก์ชันนี้จะกลับมา (หลังจากที่มีการทำหรือไม่ได้ทำส่งออกไปยังพอร์ตอนุกรม) EAX
มีมูลค่าการป้อนข้อมูลที่เหลืออยู่ใน แต่นั่นไม่ได้ผิดกฎจริงๆ ฟังก์ชั่นทั้งหมดในภาษาแอสเซมบลีจะกลับมาพร้อมกับค่าในEAX
- คำถามก็คือมันเป็นค่าที่สำคัญหรือค่าขยะ ที่กำหนดโดยเอกสารของฟังก์ชั่น (โดยหลักแล้วมันจะคืนค่าหรือส่งคืนvoid
) และในกรณีนี้ฉันกำลังจัดทำเอกสารว่าไม่ได้คืนค่า :-)
ไม่มีลิงก์ TIO สำหรับลิงค์นี้เนื่องจากไม่ได้ใช้เอาต์พุตไปยังพอร์ตอนุกรม คุณจะต้องใช้เหล็กจริงหรือจินตนาการ