x86-64 Machine Code, 8 bytes
Inspired by Bruce Forte's solution, but slightly under par. :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
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
A single integer parameter is taken in the
EDI register, following the System V AMD64 calling convention.
A copy of this value is initially made, and put into
EAX so it can be returned if appropriate. (
LEA is used instead of the normal
MOV because we need an instruction with odd bytes.)
Then, the value in
EDI is shifted right by 1, which places the shifted-off bit into the carry flag (CF). This bit will be 0 if the number was even, or 1 if it was odd.
We then test CF using the
JNC instruction, which will branch only if CF is 0 (i.e., the number was even). This means that we will go into an infinite loop for even values. For odd values, we fall through and the original value (in
EAX) is returned.
There is a bit of a trick with the
JNC instruction, though—it has a
REP prefix! Normally,
REP prefixes are only used with string instructions, but because the Intel and AMD manuals both agree that irrelevant/superfluous/redundant
REP prefixes are ignored, we throw one on the branch instruction here to make it 3 bytes long. That way, the relative offset that gets encoded in the jump instruction is also odd. (And, of course,
REP is itself an odd-byte prefix.)
RET is encoded using an odd byte!
Try it online!
In case you don't think returning the value if it's odd or going into an infinite loop if it's even (so that you never return) satisfies the "output" requirements of the challenge, or you just want something more interesting, here's a function that outputs the value to a serial port (but only if it's odd, of course).
x86-64 Machine Code (output to serial port), 17 bytes
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)
C3 ret ; return
What makes this a bit more interesting is that the code does more, which means it was more challenging to do it all using instructions that are encoded using only odd bytes. Of course, this also means that it fails at code golf, so it's kind of a tradeoff—do you want interesting and challenging, or do you want short?
Anyway, this uses the x86
OUT instruction to write to I/O port 0x3F8, which is the standard COM1 serial port on a PC. The fun part, of course, is that all standard I/O ports (serial and parallel) have even addresses, so they can't simply be encoded as immediates for the
OUT instruction or moved directly into a register. You have to initialize with one less than the actual value, and then increment the value in the register. You're also limited to using certain registers for the manipulation because you need registers that are encoded using odd bytes in the instruction when used as operands.
Also, I had to initialize the
DX register (via the
CX register) at the top of the loop, even though this is only needed if the value is odd, to ensure that the
JNC instruction would have an odd offset. However, since what we're skipping over is the
OUT instruction, all this code does is waste cycles and clobber scratch registers; it doesn't actually output anything, so it doesn't break the rules.
Finally, this function will return (after having either done or not done the output to the serial port) with the input value left in
EAX. But that doesn't actually break any rules; all functions in assembly language will return with a value in
EAX—the question is just is it a significant value or a garbage value. That's determined by the function's documentation (essentially, does it return a value or does it return
void), and in this case, I'm documenting it as not returning a value. :-)
No TIO link for this one, as it doesn't implement output to serial ports. You'll need real iron, or an imagination.