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 EDIregistro 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 MOVperché abbiamo bisogno di un'istruzione con byte dispari.)
Quindi, il valore in EDIviene 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 EAXviene restituito il valore originale (in ).
Però c'è un piccolo trucco con l' JNCistruzione: ha un REPprefisso! Normalmente, i REPprefissi 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' OUTistruzione 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 DXregistro (tramite il CXregistro) nella parte superiore del ciclo, anche se ciò è necessario solo se il valore è dispari, per garantire che l' JNCistruzione avrebbe uno scostamento dispari. Tuttavia, poiché ciò che stiamo saltando è l' OUTistruzione, 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.