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}r2define__mips_isa_revto 2.-march=mips{32,64}r3define__mips_isa_revto 3.-march=mips{32,64}r5define__mips_isa_revto 5.-march=mips{32,64}r6define__mips_isa_revto 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.