Skip to content

Instantly share code, notes, and snippets.

@rui314
Last active July 11, 2021 21:30
Show Gist options
  • Save rui314/b3a5b107ce20c2d54f345216cc15a980 to your computer and use it in GitHub Desktop.
Save rui314/b3a5b107ce20c2d54f345216cc15a980 to your computer and use it in GitHub Desktop.

MIPSのABIは変だという話をこないだのシステムプログラミング会でしたら、ややザワッとしたので、なにがおかしいのかというのをちょっとまとめてみました。まとめてみて思いましたが、やっぱりMIPSのELFファイルはちょっと変です。

謎のmixed endianフィールド

これが僕は一番ひどいと思ったものです。

ファイルにマルチバイトの数値を保存するときはエンディアンというものが問題になります。たとえば0xBEEFという2バイトの数を保存するときは、1バイト目にBE、2バイト目にEFを書くか、逆順で書くかは、ただの決まり事でどっちでもいいわけですが、書く側と読む側で認識があっていないと困ります。世の中的にはリトルエンディアン(下位バイトから書く)のが主流ですがビッグエンディアンなシステムもあります。

それがですね、MIPSのELFヘッダのr_infoという64ビットのフィールドはリトルエンディアンでもビッグエンディアンでもない謎なエンコーディングになっています。具体的には下位32ビットが最初にリトルエンディアンで書かれていて、ビッグエンディアンでエンコードされた上位32ビットがそれに続くという構成になっています。つまりリトルエンディアンだとABCD EFGH、ビッグエンディアンだとHGFE DCBAとなるところが、MIPSのmixed endianだとEFGH DCBAというふうにファイルに書かれていることになります。

このフィールドだけがこの謎のエンコードです。Mixed endianというのがあるのは知ってましたが、そういうのはPDP-11みたいな太古のコンピュータで使われていたエキゾチックなエンコーディングだとばかり思っていました。まさか現代に普通に出会うとは。別に出会いたくはなかった。

これ、なんなんでしょうか。初期の頃にバグって実装したままバグ互換でいままで続けてきたようにしか思えないんですが。

単独では解決できないリロケーション

リロケーションは普通は一つ一つ個別に処理できるものですが、MIPSの場合ペアになっているリロケーションというがあります。たとえばHI16リロケーションはLO16リロケーションが直後にあるので、両方の値を足しあわせてリロケーションを適用しないといけない、というようになっています。

これだけでも例外的なので実装が面倒なんですが、実際はGCCやClangの出力するオブジェクトファイルはこのABIさえ守っておらず、HI16とLO16がリロケーションテーブルで泣き別れになって遠く離れて入っていたりします。なのでHI16を見つけたらリロケーションをリニアサーチしないといけない。面倒なだけでなく遅くなるのでやめてほしいです。

エントリポイントの名前が違う

どんなUnixでも普通は_startという名前の関数から実行が始まります(スタティックリンクされる_startからいろいろ初期化が行われたあとユーザ定義のmainが呼ばれる)。MIPSでは__startがエントリポイントになっています。なぜかアンダースコアが一つ多い。

GOTテーブルの使い方が変

GOTテーブルの使い方に変なルールが加えられていて他のアーキテクチャ向けのELFとは違う作り方をしないといけません。もう具体的にどうなっているのかすら忘れてしまった。僕が忘れるくらいなので相当です。

リトルエンディアンとビッグエンディアンの両方が標準

普通のプロセッサではリトルエンディアンかビッグエンディアンのどちらかが標準ということになっています。x86はそもそもリトルエンディアンしかサポートしていないし、ARMやPowerPCのように両方サポートしているものでも実質はどちらかしか使われていないんですが、MIPSではなぜか両方が広く使われていて両対応しないといけません。まあこれはMIPSの問題というわけではないですが、対応が微妙に面倒。

包括的なドキュメントがない

MIPS専用のパッチが送られてくるたびにこの動作はなんなのか質問するわけですが、ABIを包括的にカバーしているドキュメントがないので何が正しいのか誰も知らないということがあります。こないだなどは、ある動作の最も信用のおけるドキュメントはGNUリンカのソースのコメントということがありました。パッチを書く人になんの罪もないわけですが、ABIみたいな基本的なところでソースが仕様みたいになっているって、どうなんでしょうか。

というわけでMIPSのELFは一応ELFではあるんですが、ところどころ作りがおかしくてMIPSバリアントみたいになってしまっています。MIPSで動くUnixの実行ファイルフォーマットが変という話であって、MIPSというCPUが変というわけではないんですが、MIPSには責任をもって直してほしいですよね。とはいえMIPSのABIのオーナーといえるのはいまは誰なんでしょう? それもいまいち謎。

Rui Ueyama (2016-07-14)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment