x86-64マシンコード、8バイト
ブルース・フォルテのソリューションに触発されましたが、わずかに標準以下です。:-)
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
ます。)
次に、値in EDI
が1だけ右にシフトされ、シフトオフされたビットがキャリーフラグ(CF)に入れられます。このビットは、数値が偶数の場合は0、奇数の場合は1になります。
次に、JNC
命令を使用してCFをテストします。この命令は、CFが0(つまり、偶数)の場合にのみ分岐します。これは、偶数の値に対して無限ループに入ることを意味します。奇数の値の場合、フォールスルーし、元の値(EAX
)が返されます。
JNC
ただし、命令にはちょっとしたトリックがありREP
ます。プレフィックスがあります!通常、REP
接頭辞は文字列命令でのみ使用されますが、IntelとAMDのマニュアルはどちらも無関係な/余分な/冗長なREP
接頭辞が無視されることに同意しているため、ここで分岐命令に1つをスローして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
これをもう少し面白くしているのは、コードがより多くのことを行うということです。つまり、奇数バイトのみを使用してエンコードされた命令を使用してすべてを行うのはより困難でした。もちろん、これはコードゴルフで失敗することを意味するため、トレードオフのようなものです。面白くてやりがいがありますか、それとも短くしたいですか?
とにかく、これはx86 OUT
命令を使用してI / Oポート0x3F8に書き込みます。これはPCの標準COM1シリアルポートです。もちろん、楽しいのは、すべての標準I / Oポート(シリアルおよびパラレル)に偶数アドレスがあるため、OUT
命令のイミディエートとして単純にエンコードしたり、レジスタに直接移動したりできないことです。実際の値より1つ少ない値で初期化してから、レジスタの値をインクリメントする必要があります。また、オペランドとして使用する場合、命令で奇数バイトを使用してエンコードされたレジスタが必要なため、特定のレジスタを操作に使用することに制限されます。
また、命令が奇数のオフセットを持つようにするために、値が奇数の場合にのみ必要ですが、ループの先頭でDX
レジスタを(レジスタを介してCX
)初期化する必要JNC
がありました。ただし、スキップしているのはOUT
命令であるため、このコードで行うことは、無駄なサイクルとスクラバーレジスタです。実際には何も出力しないため、ルールに違反しません。
最後に、この関数は、入力値をに残したまま(シリアルポートへの出力を行ったか、行わなかった後)戻りEAX
ます。しかし、それは実際にはルールを破りません。アセンブリ言語のすべての関数は、値がで返されますEAX
—問題は、それが重要な値であるか、ガベージ値であるかだけです。これは、関数のドキュメント(基本的に、値を返すか、返すか)によって決まりvoid
ます。この場合、値を返さないとドキュメントに記載しています。:-)
シリアルポートへの出力を実装していないため、これにはTIOリンクはありません。本物の鉄、または想像力が必要です。