x86-64 Codice macchina, 8 byte
Ispirato alla soluzione di Bruce Forte , ma leggermente alla pari. :-)
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
Nel EDI
registro viene preso un singolo parametro intero , seguendo la convenzione di chiamata AMD64 di System V.
Una copia di questo valore viene inizialmente creata e inserita EAX
modo che possa essere restituita, se del caso. ( LEA
è usato al posto del normale MOV
perché abbiamo bisogno di un'istruzione con byte dispari.)
Quindi, il valore in EDI
viene spostato a destra di 1, il che posiziona il bit spostato nella bandiera carry (CF). Questo bit sarà 0 se il numero era pari o 1 se fosse dispari.
Quindi testiamo CF usando il JNC
istruzione, che si dirama solo se CF è 0 (cioè, il numero era pari). Ciò significa che entreremo in un ciclo infinito per valori pari. Per valori dispari, cadiamo e EAX
viene restituito il valore originale (in ).
Però c'è un piccolo trucco con l' JNC
istruzione: ha un REP
prefisso! Normalmente, i REP
prefissi vengono utilizzati solo con le istruzioni di stringa, ma poiché entrambi i manuali Intel e AMD concordano che irrilevante / superfluo / ridondanteREP
prefissi vengono ignorati, ne lanciamo uno sulle istruzioni del ramo per renderlo lungo 3 byte. In questo modo, anche l'offset relativo che viene codificato nell'istruzione jump è dispari. (E, naturalmente, REP
è esso stesso un prefisso a byte dispari.)
Grazie a Dio RET
è codificato usando un byte dispari!
Provalo online!
Nel caso in cui non pensi di restituire il valore se è dispari o andare in un ciclo infinito se è pari (in modo da non tornare mai) soddisfa i requisiti di "output" della sfida, o vuoi solo qualcosa di più interessante, ecco una funzione che genera il valore su una porta seriale (ma solo se è dispari, ovviamente).
x86-64 Codice macchina (output su porta seriale), 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
Ciò che rende questo un po 'più interessante è che il codice fa di più , il che significa che è stato più difficile fare tutto usando le istruzioni che sono codificate usando solo byte dispari. Ovviamente, questo significa anche che fallisce nel golf del codice, quindi è una specie di compromesso: vuoi essere interessante e stimolante o vuoi in breve?
Comunque, questo usa l' OUT
istruzione x86 per scrivere sulla porta I / O 0x3F8, che è la porta seriale COM1 standard su un PC. La parte divertente, ovviamente, è che tutte le porte I / O standard (seriale e parallela) hanno indirizzi pari, quindi non possono essere semplicemente codificate come immediate perOUT
istruzione o spostate direttamente in un registro. È necessario inizializzare con uno in meno del valore effettivo e quindi incrementare il valore nel registro. Sei anche limitato all'uso di determinati registri per la manipolazione perché hai bisogno di registri che sono codificati usando byte dispari nell'istruzione quando usati come operandi.
Inoltre, ho dovuto inizializzare il DX
registro (tramite il CX
registro) nella parte superiore del ciclo, anche se ciò è necessario solo se il valore è dispari, per garantire che l' JNC
istruzione avrebbe uno scostamento dispari. Tuttavia, poiché ciò che stiamo saltando è l' OUT
istruzione, tutto questo codice fa è cicli di scarto e registri dei graffi di clobber; in realtà no uscita nulla, quindi non si rompe le regole.
Infine, questa funzione tornerà (dopo aver eseguito o meno l'output sulla porta seriale) con il valore di input lasciato in EAX
. Ma ciò in realtà non infrange alcuna regola; tutte le funzioni nel linguaggio assembly torneranno con un valore in EAX
— la domanda è solo se è un valore significativo o un valore di immondizia . Ciò è determinato dalla documentazione della funzione (essenzialmente, restituisce un valore o restituisce void
) e, in questo caso, lo sto documentando come non restituendo un valore. :-)
Nessun collegamento TIO per questo, in quanto non implementa l'output alle porte seriali. Avrai bisogno di ferro vero o di un'immaginazione.