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
, andmove
that assemble to one or more real machine instructions.addiu
is 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
move
mnemonic. Adding or ORing an immediate0
, or a zero from reading the$zero
register, 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
move
pseudo-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 amove
depends on the assembler.I'm not sure what the point of a
move
with a destination of$zero
is. That would be a no-op, because$zero
discards writes. (It's the CPU-register equivalent of/dev/zero
)