I'm trying to understand how to decode MIPS binary instructions.
I compiled a hello world program in C on a Debian MIPS system with gcc and objdump shows me that the first instruction in the .text section is:
600: 03e00025 move zero,ra
I don't understand how it determines that this is the MOVE instruction.
03e00025 is 00000011111000000000000000100101 in binary. If I understand correctly the first 6 bits here are the opcode, which in this case is all 0, meaning it's an R-type instruction, so we have to look at the last 6 bits, which is 100101. Looking at the MIPS Instruction Set Manual it looks like this should be the OR instruction. I can't even find MOVE in that manual.
Googling for this I found that apparently there are "pseudo" instructions in the assembly, and supposedly move $t, $s expands to addiu $t, $s, 0, but if I look in the manual ADDIU has opcode 001001. Another result I found claims it translates to ADD but the last six bits of ADD should be 100000, so that doesn't fit either.
What am I missing?
MIPS machine code doesn't have a specific opcode for
move, but for the convenience of humans, many assemblers support pseudo-instructions likeli,la, andmovethat assemble to one or more real machine instructions.addiuis a common one.It would be totally correct for objdump to decode the instruction as
or $0, $ra, $0(according to Jester) to show you how it's actually encoded.For some purposes it makes sense for a disassembler to decode any of the commonly used ways to copy a register into a
movemnemonic. Adding or ORing an immediate0, or a zero from reading the$zeroregister, do nothing to the value so it's copied unchanged.When reading the asm, you normally don't care whether it's
or,ori,addiu $0, $ra, 0, or whatever.Different assemblers might use different implementations for the
movepseudo-instruction, or hand-written asm could use any of them. I don't think there are any performance consequences either way. So the details of which machine instruction is used to implement amovedepends on the assembler.I'm not sure what the point of a
movewith a destination of$zerois. That would be a no-op, because$zerodiscards writes. (It's the CPU-register equivalent of/dev/zero)