# The questions about li instruction

When reversing a MIPS binary using IDA Pro, I have 2 questions. The source code is as follows.

``````int main(int argc, char* argv[])
{
int m = 1;
int n = 5;
printf("sum = %d\n", m+n);
}
``````

## ``````.text:00080510  # int __cdecl main(int argc, const char **argv, const char **envp)

.text:00080510  .globl main
.text:00080510  main:
.text:00080510      # __unwind {
.text:00080510 02 00 1C 3C 00 8B 9C 27  li      \$gp, 0x18B00
.text:00080518 21 E0 99 03              addu    \$gp, \$t9
.text:0008051C 1C 80 84 8F              li      \$a0, 0x80000
.text:00080520 44 80 99 8F              la      \$t9, printf
.text:00080524 A4 08 84 24              addiu   \$a0, (aSumD - 0x80000)  # "sum = %d\n"
.text:00080528 08 00 20 03              jr      \$t9 ; printf
.text:0008052C 06 00 05 24              li      \$a1, 6
.text:0008052C                  # } // starts at 80510
.text:00080530
``````

(1) I know the li instruction at offset 0x0008051c is lw actually. And its encoding format is 1000 11ss ssst tttt iiii iiii iiii iiii. So I konw sssss = (111100)2 = 28 = \$gp, ttttt = (00100)2 = 4 = \$a0. But I don't know how to calculate 0x80000.

(2) The li instrution at offset 0x00080510 takes 8 bytes, but another li instruction at offset 0x0008051C takes 4 bytes? Is the first li instruction a pseudoinstruction?

MIPS instructions are 4 bytes (32 bit) in size. Hence it's not possible to load a 32 bit constant using a single instruction.

The `li \$gp, 0x18B00` instruction is indeed a pseudo instruction. It's composed of two instructions.

``````lui     gp, 0x2
``````

Screenshot from Online Disassembler The `lui` (Load Upper Immediate) instruction loads a 16-bit constant into the upper 16 bits of a register (`\$gp` here).

The `addiu` instruction adds a 16 bit integer to a register. The final value in `\$gp` can be calculated as:

``````\$gp = (2 << 16) + (-29952) = 0x18B00
``````

IDA pro and other disassemblers does this calculation automatically and displays the final result using a single pseudo instruction.

The other `li \$a0, 0x80000` instruction at `0008051C` is actually a `lw` (Load Word) instruction. The `lw` instruction loads a word from memory into a register. The value `0x80000` is thus located in memory at `[\$gp - 32740]` and not a part of the instruction itself.

IDA however simplifies and shows it as `li \$a0, 0x80000` as the net result is the value `0x80000` is copied to the register.

• Thank you very much! in question (1), how to calculate the 0x80000? – user6903 Mar 25 '20 at 10:31
• @user6903 Check update – 0xec Mar 25 '20 at 10:50
• Now is static analysis, how does IDA calculate the value of the \$gp register, that is, how to calculate \$gp - 32740 ? – user6903 Mar 25 '20 at 11:14
• The very first instruction sets the value of the `\$gp` register `li \$gp, 0x18B00` – 0xec Mar 25 '20 at 11:40
• There's a way to turn off IDA simplifying gp references. Check this – 0xec Mar 25 '20 at 11:42