Open Design Computer Project

オリジナルCPUから作る本格的自作コンピューター

ユーザ用ツール

サイト用ツール


software:porting_binutils

新アーキテクチャに GNU binutils を移植

GNU binutils 及び GNU as (gas) を新たな独自命令セットのプロセッサアーキテクチャ向けに対応・移植させるためのドキュメントです。

mist32 アーキテクチャ (RISC, 32bit, 固定長) 向けに binutils を移植した一例を書き留めておきます。

今後新たなアーキテクチャが開発された時、アセンブラ・コンパイラの移植の際の参考になればと思います。

binutils について

binutils は以下ののようなユーティリティとその周辺のソフトウェアで構成されています。

  • BFD Library
  • as (gas) [Assembler]
  • ld [Linker]
  • objdump [Disassembler]

(最近の binutils のリポジトリは、gdb も一緒になっています。)

binutils を新たなアーキテクチャ向けに移植することで、そのアーキテクチャ向けの上記のツールを使うことができるようになります。

特に、コンパイラを開発する上でアセンブラは必ず必要になりますし、コンパイラに gcc を採用した場合親和性が高い gas を移植することになるでしょう。

また、その他バイナリ関連のユーティリティ群をまとめて移植することで、強力な開発環境を構築することができます。

mist32 の移植例

参考にしてみてください。HEAD と rebase 直前の commit の diff を取ると良いかと思います。

CGEN の移植

今回、binutils の移植をするために CGEN を利用しました。

CGEN を利用せず移植することもできますが、今回は CGEN を利用する前提で進めます。

比較的最近出てきたツールで、m32c, m32r, fr30, frv, openrisc などのアーキテクチャがこれを利用しています。

bfd ライブラリの移植

ELF 形式やリンカについて詳しく知っていないと、移植するのが結構難しい。

リンカ・ローダ実践開発テクニック という本がとても良いです。これを見て、ELF と仲良くなってから望むのが良いと思います。

REL と RELA

基本的に RISC は RELA です。後述して出てくる概念で、日本語であまり解説がないので迷わないように。

REL と RELA の違いは、ELF のリロケーション(再配置)が行われる時に、どのようにリロケーション元のアドレスが格納されるか、それをどうやって計算するかの違いです。RELA が必要なのは、RISC 系の CPU のためだという事らしいです。その CPU が対応する即値フィールドのビット数以上のオフセットを格納できませんからね。

REL は、命令中にシンボルからのオフセットが含まれています。リロケーション時には、シンボルが配置された位置を、命令中に配置されているオフセットと加算します。

RELA は、.rela セクションの情報の中に、シンボルからのオフセットが含まれるようになります。(Elf32_Rela の r_addend) 再配置前の命令列中には、0 が配置されてます。

後述する HOWTO マクロのところで出てくる partial_inplace というフィールドがこれに深く関係していて、つまり RELA であれば FALSE になります。

bfd/cpu-mist32.c

bfd_arch_info_type を記述する。

mist32 の例

const bfd_arch_info_type bfd_mist32_arch =
{
   32,                          /* 32 bits in a word.  */
   32,                          /* 32 bits in an address.  */
   8,                           /* 8 bits in a byte.  */
   bfd_arch_mist32,             /* Architecture.  */
   0,                           /* Machine number - 0 for now.  */
   "mist32",                    /* Architecture name.  */
   "mist32",                    /* Printable name.  */
   2,                           /* Section align power.  */
   TRUE,                        /* This is the default architecture.  */
   bfd_default_compatible,      /* Architecture comparison function.  */
   bfd_default_scan,            /* String to architecture conversion.  */
   bfd_arch_default_fill,       /* Default fill.  */
   NULL                         /* Next in list.  */
};

bfd/elf32-mist32.c

ELF オブジェクトのリロケーションに関する以下の情報を記述する。

  • ELF に関する定義 (ELF_ARCH, ELF_MACHINE_CODE など)
  • mist32_elf_howto_table
    • リロケーション HOWTO の定義
    • それに設定する独自のハンドラの定義も書く
    • 後述の HOWTO マクロ参照
  • mist32_reloc_map
    • リロケーションの対応表
    • オペランドとの対応付けは gas/config/tc-mist32.c で行われている
  • その他関数
    • elf_info_to_howto (RELA はこっち, REL なら _rel を定義する)
    • elf_backend_relocate_section
    • elf_backend_gc_mark_hook
    • elf_backend_check_relocs
    • elf_backend_rela_normal (RELA なら 1)
    • elf_backend_can_gc_sections
    • bfd_elf32_bfd_reloc_type_lookup
    • bfd_elf32_bfd_reloc_name_lookup
    • 他のアーキテクチャを参考に頑張りましょう。

だいたいこんな感じ。

HOWTO マクロ

bfd/reloc.c またはここの 2.10.1.2 reloc_howto_type に詳しい説明がある。

PC relative な 16bit アドレスオペランドの例。32bit なワード境界にしか命令を割り当てることはないので、2bit 右シフトされた状態で格納される。また、RELA relocation なので、partial_inplace は FALSE, src_mask は 0 になる。

  /* A PC relative signed 16 bit relocation, right shifted by 2.  */
  HOWTO (R_MIST32_INSN_REL_16,  /* type */
         2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_MIST32_INSN_REL_16", /* name */
         FALSE,                 /* partial_inplace */
         0x00000000,            /* src_mask */
         0x0000ffff,            /* dst_mask */
         TRUE),                 /* pcrel_offset */

include/elf/mist32.h

START_RELOC_NUMBERS, END_RELOC_NUMBERS でリロケーションの番号を指定する。

gas の移植

gas/config/tc-mist32.c, tc-mist32.h

gas に関する関数・マクロを定義します。

md_begin, md_assemble などは cgen を使う場合、cgen の関数を呼び出すことになります。

md_cgen_lookup_reloc では、オペランドとリロケーションの対応付けを定義します。

Build

必要なもの

–enable-maintainer-mode を使うので以下のツール群 (README-maintainer-mode 参照)

  • autoconf 2.64
  • automake 1.11
  • libtool 2.2.6
  • gettext 0.14.5

その他に以下のツールが必要

    • cvs 版を使ったほうがよい。cgen-1.1 (tarで配布されている最新版) では古くて動かなかった。
  • guile (>= 1.8)
  • bison
  • flex

automake, configure

binutils では autoconf, automake (autotools) が使われていて、configure はこれらによって生成されている。 Makefile.in をいじってる関係で、それぞれのディレクトリで autoreconf する必要がある。

ただしバージョンがあっていないと以下のように言われることがある。 なぜか、2.64 の autoconf を使っても、システムに他のバージョンがあるとこれを言われることがある。

$ autoreconf
configure.ac:34: error: Please use exactly Autoconf 2.64 instead of 2.69.
config/override.m4:12: _GCC_AUTOCONF_VERSION_CHECK is expanded from...
configure.ac:34: the top level
autom4te: /usr/bin/m4 failed with exit status: 1
aclocal: autom4te failed with exit status: 1
autoreconf: aclocal failed with exit status: 1

Debian wheezy の autoconf2.64 というパッケージを入れて、autoreconf2.64 というコマンドを叩けばこう言われることはない。

もしどうしてもうまくいかない場合には、全部無理やり libtoolize, aclocal, autoreconf し直すという方法もある。 もっと良い解決方法がありそうだが、これでもどうにかうまくいく。

cp -r /path/to/cgen/src/cgen /path/to/binutils-mist32
 
libtoolize -f -c --recursive; aclocal; autoreconf -i
cd binutils
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../bfd
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../gas
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../ld
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../opcodes
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../gprof
libtoolize -f -c; aclocal -I ..; autoreconf -i
cd ../

以下の様な感じで configure する。

mkdir build
cd build
../binutils-mist32/configure --target=mist32-elf --program-prefix=mist32-elf- --disable-gdb --prefix=/usr/local

make

とりあえず make する。

うまく行かない場合は、いちど make distclean したあとに configure, make しなおす。

config.cache を消すのを忘れずに。(なぜか distclean で失敗します)

cgen で opcodes のソースコードを生成

$ make
make[4]: *** `opcodes.pot' に必要なターゲット `../mist32-asm.c'make するルールがありません.  中止.

cgen で opcodes 関連のコードを自動生成。

$ cd opcodes
$ make stamp-mist32

あとは、make を再開して、make install しておわり。

参考資料

software/porting_binutils.txt · 最終更新: 2015/04/27 01:31 by hktechno