---
# System prepended metadata

title: Characteristics of Nintendo 64 compiler output

---

# Characteristics of Nintendo 64 compiler output

Or: heuristics for distinguishing them.

## General compiler stuff

### IDO

* Unconditional branches use `b`.
* Float literals can be loaded with `lui` followed by `mtc1` or from rodata with `lui` and `lwc1`. These can be reordered among other instructions in the function. (It seems to never use `lui`, `ori`, `mtc1` but this needs to be verified)
* This is the only compiler where an instruction that isn't `mfhi` or `mflo` can follow a `break 6`.
  * The expansion of division and modulus for ido in general allows for reorderings that the other compilers don't have, but this is the easiest to check.
* (-g only) The compiler will emit `b after; nop; after:` frequently. These are the words 0x10000001 0x00000000.

### KMC GCC (2.7.2)
* Unconditional branches use `j`.
* Float literals will always be loaded with a sequence of `lui`, an optional `ori`, and `mtc1` with the GPR used for all three being $at. These are always directly sequential.
* `break 6` will always be followed by `mfhi` or `mflo`. `break 7` will always be followed by `mfhi`, `mflo`, or `addiu       $at, $zero, -0x1` (exactly).

### GCC 2.8(?)
* Function epilogue (`addiu $sp, $sp, X`, `jr $ra`) can be omitted after an infinite loop.

### SN64
* Unconditional branches use `j`.
* Float literals will always be loaded with a sequence of `lui` and `lwc1` with the GPR being used for both being $at. These are always directly sequential.
* `mtc1 $at, ...` is *never* emitted.
* `break 6` will always be followed by `mfhi` or `mflo`. `break 7` will always be followed by `mfhi`, `mflo`, or `addiu       $at, $zero, -0x1` (exactly).

## MIPS levels

### MIPS I
* requires a `nop` after certain loads (TODO: which?)

### MIPS III
* An unencumbered `-mips3` (not patched as in e.g. KMC) will use `daddiu` etc. for loads (see e.g. iQue)

# Entrypoints

## makerom

Original assembly looks like
```mips
 la    $8 <BssStart>
 li    $9 <bssSize>
1:
 sw $0, 0($8)
 sw $0, 4($8)
 addi $8, 8
 addi $9, 0xfff8
 bne $9, $0, 1b
 la    $29 <bootStack>
 la $10  <bootEntry>
 j $10
```

The symbols in `<>` are all written as numeric constants. IDO will expand `la` to `(lui)/addiu` and `li` to `(lui)/ori` in such cases; `j` expands to `jr`.

## mild

```mips
    la    $8,_%sSegmentBssStart
    la    $9,_%sSegmentBssSize
1:
    sw    $0, 0($8)
    sw    $0, 4($8)
    addi    $8, 8
    addi    $9, 0xfff8
    bne    $9, $0, 1b
    la    $10,%s # bootEntry
    la    $29,%s # bootStack
    jr    $10
```

(not 100% confirmed but very likely from reading it from the binary). The instructions all use *symbols*, which GCC expands as `lui/addiu`.

## SN64

There are several versions of the entrypoint for SN64. 
* The main distinguishing common factors between them is that they all have `li $sp, 0x803FFFF0` (aka `lui  $sp, 0x803F` followed by `ori $sp, $sp, 0xFFF0`) and that they use a `jal` for calling the bootproc instead of `jr`.
* `break` also appears frequently, although some custom versions do not use it.
