UNDER CONSTRUCTION
This article describes some notes about MIPS with a focus on the ELF object file format, GCC, binutils, and LLVM/Clang.
ISAs
Earlier ISAs, such as MIPS I, MIPS II, MIPS III, and MIPS IV, can be
selected by gcc -march=mips[1-4]
. MIPS V has no
implementation and GCC doesn't support -march=mips5
.
Successive versions are split into MIPS32 and MIPS64, which can be
selected by -march=mips{32,64}
and
-march=mips{32,64}r{2,3,5,6}
.
-march=mips{32,64}r4
is not supported.
Release 6 is very different from prior releases.
-march=mips{32,64}r2
define__mips_isa_rev
to 2.-march=mips{32,64}r3
define__mips_isa_rev
to 3.-march=mips{32,64}r5
define__mips_isa_rev
to 5.-march=mips{32,64}r6
define__mips_isa_rev
to 6.- Older processors don't define
__mips_isa_rev
.
The ISA revisions of GCC supported -march=
values can be
found at gcc/config/mips/mips-cpus.def
.
The EF_MIPS_ARCH
(0xf0000000) part of
e_flags
indicates the ISA.
When a 64-bit capable CPU is used with o32, assemblers set the
EF_MIPS_32BITMODE
flag in e_flags
.
ABIs
o32
https://refspecs.linuxfoundation.org/elf/mipsabi.pdf
This is an ILP32 ABI designed for the 32-bit CPU MIPS R3000 that implements the MIPS I ISA. It is the original System V Processor Supplement ABI for MIPS.
In GCC, -mabi=32
selects this ABI, which is identified
as ABI_32
.
Assemblers set the EF_MIPS_ABI_O32
flag in
e_flags
.
There are some major flaws:
- The calling convention provides just 4 integer registers for arguments (inadequate).
- The ABI is committed to MIPS I and makes odd-numbered floating-point registers inaccessible.
- Only two floating-point registers $12 and $14 hold arguments. The rest use integer registers, which are severely limited.
MIPS I has 32 floating-point registers. Two registers are paired for holding a double precision number.
- For single-precision values, the even-numbered floating-point register holds the value.
- For double-precision values, the even-numbered floating-point register holds the least significant 32 bits of the value and the odd-numbered floating-point register holds the most significant 32 bits of the value.
For o32, -mfp64
selects a variant that enables 64-bit
floating-point registers. This requires at least
-march=mips32r2
and GCC will emit
.module fp=64; .module oddspreg
.
n64
This is an LP64 ABI designed for 64-bit CPUs (MIPS III and newer).
In GCC, -mabi=64
selects this ABI, which is identified
as ABI_64
.
Assemblers don't set a particular bit in e_flags
.
n32
This is an ILP32 ABI for 64-bit CPUs (MIPS III and newer), often named n32.
In GCC, -mabi=n32
selects this ABI, which is identified
as ABI_N32
. -march=
values such as
mips3, mips64
are compatible.
Assemblers set the EF_MIPS_ABI2
bit in
e_flags
.
o64
This is o32 extended for 64-bit CPUs. https://gcc.gnu.org/projects/mipso64-abi.html
In GCC, -mabi=o64
selects this ABI, which is identified
as ABI_O64
.
Assemblers set the EF_MIPS_ABI_O64
flag in
e_flags
.
EABI
Assemblers set the EF_MIPS_ABI_EABI32
flag in
e_flags
.
o32 and o64 are called TARGET_OLDABI
in GCC. n32 and n64
are called TARGET_NEWABI
in GCC.
gcc/config.gcc
defines the default ABI (macro
MIPS_ABI_DEFAULT
) for different target triples.
In the old ABIs, the local label prefix for assembly is
$
, which is strange.
GCC emits a special section to indicate the ABI for GDB.
- o32:
.mdebug.abi32
- n32:
.mdebug.abiN32
- n64:
.mdebug.abi64
- o64:
mdebug.abiO64
- 32-bit EABI:
.mdebug.eabi32
- 64-bit EABI:
.mdebug.eabi64
gp register
Floating-point numbers
See NaN encodings.
IEEE 754-2008 says
A quiet NaN bit string should be encoded with the first bit (d1) of the trailing significand field T being 1.
-mnan=2008
instructs GCC to emit a
.nan 2008
directive, which causes GNU assembler to set the
EF_MIPS_NAN2008
bit in e_flags
.
MIPS32/MIPS64 Release 6 defaults to -mnan=2008
while
prior ISAs default to -mnan=legacy
.
-modd-spreg
for o32
Enable the use of odd-numbered single-precision floating-point
registers for the o32 ABI. This option requires
-march=mips32
or above.
I think the option should not be used with n32 or n64.
1 | % grep DT_MIPS_ include/elf/mips.h |
Among these dynamic tags, DT_MIPS_LOCAL_GOTNO
,
DT_MIPS_GOTSYM
, DT_MIPS_SYMTABNO
, and
DT_MIPS_PLTGOT
have significant uses in glibc rtld.
For executable output, DT_MIPS_RLD_MAP_REL
holds the
offset to the linker synthesized .rld_map
. If
DT_MIPS_RLD_MAP_REL
is unavailable, glibc rtld looks for
DT_MIPS_RLD_MAP
, which is emitted for ET_EXEC
executables.
Special sections
There are many special sections. Let me just quote a comment from
binutils/readelf.c:process_mips_specific
:
1 |
There are many sections from other vendors. Anyway, this remark sets up the mood.
.reginfo
section
GNU assembler creates this section to hold Elf32_RegInfo
object for o32 and n32 ABIs.
1 |
|
.MIPS.options
section
The n64 ABI uses .MIPS.options
instead of
.reginfo
.
.MIPS.abiflags
section
In 2014, [MIPS]
Implement O32 FPXX, FP64 and FP64A ABI extensions introduced
.MIPS.abiflags
(type SHT_MIPS_ABIFLAGS
) and
PT_MIPS_ABIFLAGS
.
1 | A new implicitly generated section will be present on all new modules. The section contains a versioned data structure which represents essential information to allow a program loader to determine the requirements of the application. ELF e_flags currently contain some of this information but space is limited and e_flags are not available after loading an application. |
GNU ld has quite involved merging strategy for this section.
Relocations
The little-endian n64 ABI messed up the r_info
field in
relocations.
The n64 ABI can pack up to 3 relocations with the same offset into one record.
R_MIPS_PC64
This relocation type does not exist, but we can emulate a 64-bit
PC-relative relocation with
R_MIPS_PC32 + R_MIPS_64 + R_MIPS_NONE
. LLVM implemented
this relocation in https://reviews.llvm.org/D80390 while binutils doesn't
support it yet.
1 | .globl foo |
Paired relocations
TODO
Distributions
Here is an incomplete list.
- https://www.debian.org/ports/mips/
- https://fedoraproject.org/wiki/Architectures
- https://wiki.gentoo.org/wiki/Project:MIPS
- https://wiki.netbsd.org/ports/
- https://www.openbsd.org/plat.html
- https://openwrt.org/docs/techref/targets/start
FreeBSD 14 discontinued MIPS. MIPS code was removed starting since 2021-12.
Misc
E_MIPS_*
macros are considered
deprecated.