Code machine x86-64, 8 octets
Inspiré par la solution de Bruce Forte , mais légèrement en dessous de la normale. :-)
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
Un seul paramètre entier est pris dans le EDI
registre, conformément à la convention d'appel System V AMD64.
Une copie de cette valeur est initialement créée et insérée EAX
pour pouvoir être renvoyée le cas échéant. ( LEA
est utilisé à la place de la normaleMOV
car nous avons besoin d'une instruction avec des octets impairs.)
Ensuite, la valeur dans EDI
est décalée de 1, ce qui place le bit décalé dans l'indicateur de retenue (CF). Ce bit sera 0 si le nombre était pair, ou 1 s'il était impair.
Nous testons ensuite CF en utilisant l’ JNC
instruction, qui ne se branche que si CF est 0 (c’est-à-dire que le nombre était pair). Cela signifie que nous allons entrer dans une boucle infinie pour des valeurs paires. Pour les valeurs impaires, nous échouons et la valeur d'origine (in EAX
) est renvoyée.
Il y a un petit truc avec l' JNC
instruction, cependant - elle a un REP
préfixe! Normalement, les REP
préfixes ne sont utilisés qu'avec des instructions string, mais comme les manuels d'Intel et d'AMD conviennent que les REP
préfixes non pertinents / superflus / redondants sont ignorés, nous en jetons un sur l'instruction de branche ici pour lui donner une longueur de 3 octets. De cette façon, le décalage relatif encodé dans l'instruction de saut est également impair. (Et, bien sûr, REP
est lui-même un préfixe d'octet impair.)
Dieu merci, il RET
est encodé avec un octet impair!
Essayez-le en ligne!
Si vous pensez ne pas renvoyer la valeur si elle est impaire ou si vous entrez dans une boucle infinie si elle est paire (pour que vous ne retourniez jamais) satisfait aux exigences de sortie du défi, ou si vous voulez juste quelque chose de plus intéressant, voici une fonction qui envoie la valeur sur un port série (mais seulement si c'est impair, bien sûr).
Code machine x86-64 (sortie sur le port série), 17 octets
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
Ce qui rend cela un peu plus intéressant, c'est que le code en fait plus , ce qui signifie qu'il était plus difficile de tout faire en utilisant des instructions codées en utilisant uniquement des octets impairs. Bien sûr, cela signifie aussi que cela échoue au code golf, donc c'est un peu un compromis - voulez-vous un défi intéressant ou exigeant, ou voulez-vous un court-métrage?
Quoi qu'il en soit, cela utilise l' OUT
instruction x86 pour écrire sur le port d'E / S 0x3F8, qui est le port série COM1 standard sur un PC. La partie amusante, bien sûr, réside dans le fait que tous les ports d’E / S standard (série et parallèle) ont même une adresse. Ils ne peuvent donc pas simplement être codés comme des OUT
instructions immédiates pour l’ instruction ou être déplacés directement dans un registre. Vous devez initialiser avec un moins que la valeur réelle, puis incrémenter la valeur dans le registre. Vous êtes également limité à l'utilisation de certains registres pour la manipulation, car vous avez besoin de registres codés en utilisant des octets impairs dans l'instruction lorsqu'ils sont utilisés en tant qu'opérandes.
De plus, je devais initialiser le DX
registre (via le CX
registre) en haut de la boucle, même si cela n’est nécessaire que si la valeur est impair, pour que l’ JNC
instruction ait un décalage impair. Cependant, puisque nous omettons l’ OUT
instruction, ce code ne fait que gaspiller des cycles et des registres de grattage clobber; en réalité , il ne génère rien, il n'enfreint donc pas les règles.
Enfin, cette fonction retournera (après avoir fait ou non la sortie vers le port série) avec la valeur d’entrée laissée EAX
. Mais cela n'enfreint aucune règle; toutes les fonctions en langage assembleur renverront une valeur EAX
- la question est simplement de savoir s'il s'agit d'une valeur significative ou d'une valeur erronée . Cela est déterminé par la documentation de la fonction (en gros, est-ce qu'elle renvoie une valeur ou est-elle renvoyée void
), et dans ce cas, je la documente comme ne renvoyant pas de valeur. :-)
Pas de lien TIO pour celui-ci, car il n'implémente pas la sortie sur les ports série. Vous aurez besoin d'un vrai fer ou d'une imagination.