Mã máy x86-64, 8 byte
Lấy cảm hứng từ giải pháp của Bruce Forte , nhưng hơi dưới mệnh. :-)
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
Một tham số nguyên duy nhất được lấy trong thanh EDI
ghi, theo quy ước gọi System64 AMD.
Một bản sao của giá trị này ban đầu được tạo ra và đưa vào EAX
để có thể trả lại nếu thích hợp. ( LEA
được sử dụng thay vì bình thườngMOV
vì chúng ta cần một lệnh có byte lẻ.)
Sau đó, giá trị trong EDI
được dịch chuyển sang phải 1, trong đó đặt bit đã chuyển sang cờ mang (CF). Bit này sẽ là 0 nếu số chẵn hoặc 1 nếu là số lẻ.
Sau đó, chúng tôi kiểm tra CF bằng cách sử dụng JNC
hướng dẫn, sẽ chỉ phân nhánh nếu CF bằng 0 (nghĩa là số chẵn). Điều này có nghĩa là chúng ta sẽ đi vào một vòng lặp vô hạn cho các giá trị chẵn. Đối với các giá trị lẻ, chúng tôi rơi vào và giá trị ban đầu (in EAX
) được trả về.
Có một chút mẹo với JNC
hướng dẫn, mặc dù vậy, nó có REP
tiền tố! Thông thường, REP
các tiền tố chỉ được sử dụng với các hướng dẫn chuỗi, nhưng vì các hướng dẫn sử dụng của Intel và AMD đều đồng ý rằng không liên quan / không cần thiết / dư thừaREP
các tiền tố bị bỏ qua, chúng tôi ném một lệnh vào nhánh ở đây để làm cho nó dài 3 byte. Theo cách đó, phần bù tương đối được mã hóa trong lệnh nhảy cũng là số lẻ. (Và tất nhiên,REP
bản thân nó là một tiền tố byte lẻ.)
Cảm ơn lòng tốt RET
được mã hóa bằng một byte lẻ!
Hãy thử trực tuyến!
Trong trường hợp bạn không nghĩ trả về giá trị nếu nó lẻ hoặc đi vào một vòng lặp vô hạn nếu nó thậm chí (để bạn không bao giờ quay lại) đáp ứng các yêu cầu "đầu ra" của thử thách hoặc bạn chỉ muốn một cái gì đó thú vị hơn, đây là một hàm điều đó đưa giá trị ra một cổng nối tiếp (tất nhiên chỉ khi nó là số lẻ).
Mã máy x86-64 (đầu ra cổng nối tiếp), 17 byte
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
Điều làm cho điều này thú vị hơn một chút là mã làm được nhiều hơn , điều đó có nghĩa là khó khăn hơn khi thực hiện tất cả bằng cách sử dụng các hướng dẫn được mã hóa chỉ bằng các byte lẻ. Tất nhiên, điều này cũng có nghĩa là nó thất bại ở môn đánh gôn, vì vậy đây là một sự đánh đổi mà bạn muốn thú vị và đầy thách thức, hay bạn muốn ngắn?
Dù sao, công dụng này x86 OUT
hướng dẫn để ghi vào I / O port 0x3F8, đó là tiêu chuẩn COM1 cổng nối tiếp trên một máy tính. Tất nhiên, điều thú vị là tất cả các cổng I / O tiêu chuẩn (nối tiếp và song song) đều có địa chỉ chẵn, vì vậy chúng không thể được mã hóa thành lệnh ngay lập tức cho OUT
hướng dẫn hoặc chuyển trực tiếp vào thanh ghi. Bạn phải khởi tạo với một giá trị nhỏ hơn giá trị thực và sau đó tăng giá trị trong thanh ghi. Bạn cũng bị giới hạn trong việc sử dụng các thanh ghi nhất định cho thao tác vì bạn cần các thanh ghi được mã hóa bằng các byte lẻ trong hướng dẫn khi được sử dụng làm toán hạng.
Ngoài ra, tôi đã phải khởi tạo thanh DX
ghi (thông qua thanh CX
ghi) ở đầu vòng lặp, mặc dù điều này chỉ cần nếu giá trị là số lẻ, để đảm bảo rằng JNC
lệnh sẽ có phần bù lẻ. Tuy nhiên, vì những gì chúng ta bỏ qua là OUT
hướng dẫn, tất cả các mã này làm là lãng phí chu kỳ và các thanh ghi cào; nó không thực sự xuất ra bất cứ thứ gì, vì vậy nó không phá vỡ các quy tắc.
Cuối cùng, chức năng này sẽ trở lại (sau khi đã hoàn thành hoặc không thực hiện đầu ra cho cổng nối tiếp) với giá trị đầu vào còn lại EAX
. Nhưng điều đó không thực sự phá vỡ bất kỳ quy tắc nào; tất cả các chức năng trong ngôn ngữ lắp ráp sẽ trả về với một giá trị trong EAX
câu hỏi chỉ là một giá trị quan trọng hoặc giá trị rác . Điều đó được xác định bởi tài liệu của hàm (về cơ bản, nó trả về một giá trị hay nó trả về void
) và trong trường hợp này, tôi đang ghi lại nó là không trả về giá trị. :-)
Không có liên kết TIO cho cái này, vì nó không thực hiện đầu ra cho các cổng nối tiếp. Bạn sẽ cần sắt thực sự, hoặc một trí tưởng tượng.