I expected this:
.org 0x0000
RET
.org 0x0002
RET
to produce this:
C9
00
C9
This is incorrect. 0x00 is usually NOP, but there is no NOP in your code.
ORG don't produce code, it just setup a new instruction pointer.
This is what happens in your code:
.org 0x0000 ; the next instruction should be placed at 0x0000
RET ; this instruction is placed at 0x0000
.org 0x0002 ; the next instruction should be placed at 0x0002
RET ; this instruction is placed at 0x0002
there are just two ret's, so the compilation result will be:
0x0000: 0xc9
0x0002: 0xc9
so, the correct result is just two 0xc9, but their addresses are not sequential, first one is placed at 0x0000 and second one is placed at 0x0002.
If compiler fills 0x00 between 0xc9 - this is serious bug of the compiler.
If it just filled in the gaps with 0 and did this in the ".bin" file I'd be golden.
The BIN output format does not support multiple ORG directives. Technically, the compiler should reject such input and avoid generating a BIN file, however, some compilers may not report an error and instead produce a BIN file with undefined or incorrect content. In some implementations, filling the gaps with zeros in BIN for this case is not a bug but a documented behavior, since the BIN format lacks a mechanism to represent address gaps, unlike formats such as HEX.
If your code contains multiple ORG directives, then you need to use the HEX output format instead of BIN.