2015年03月16日

binutils2.22以降でARMでinterworkingするアセンブラ関数を書く場合には%function属性が必須

タイトルでほぼ終わりなのですが、binutils 2.22 以降では、以下のようにアセンブラのみで書かれた関数には %function 属性を付けないと、正しく ARM コードと thumb コードで interworking できないのでちゃんと付けましょう、というだけの話です…が、原因がわかるまでけっこう悩んだので経緯をメモしておきます。
    。。。。
    .global     foo
    .type        foo, %function
foo:
    。。。。


古い ARM11 向けのサンプルコードを、GCC 4.8.4 + binutils 2.25 でビルドした所、ARM では期待通り動作するのですが、thumb(一部に ARM コードが含まれるので interworking)では動作せず、原因を切り分けて行った所、GNU ld のみを 2.21.1(弊社の exeGCC4 r003 の binutils のバージョンが 2.21 で、サンプルはこれで動作確認されたものだったので)に差し替えると動作するということがわかりました。

デバッガで追って見ると、自動生成されるスタブ XXX_from_arm や XXX_from_thumb の辺りに差異があり、当初はまだあまり実績が無い最新版の 2.25 だしと ld のバグを疑ったりもしたのですが、その後の調査で 2.22 以降が全滅ということがわかり、これはおそらく何か仕様変更があったのだろうと思いつつも、その時はそれ以上はわからず、しかたがないので 2.21.1 でビルドしていたのですが、これはさすがに古く、Ubuntu 14.04 では素直に MinGW 版がクロスビルドできないなど、いろいろと問題がありました。

そんなこんなでいつかは解決したいなと思いつつも後回しにされていたこの問題ですが、最近別件で調べものをしていて、ふとしたことから以下のメーリングリストでのやり取りにたどり着き、無事解決しました。

latest ld not inserting arm interworking shims?
binutils 2.21.1 では期待通り動作するのに 2.22 では動作しないということで、私のケースとバージョンがドンピシャだったこともあり、ピンときました。
この質問者と、%function 属性が必要という素晴らしい回答者に感謝です。

わかってしまえば当たり前で、なぜ 2.21 以前はここらへんがいい加減でも動いていたのか、むしろ不思議に思えます。2.21 以前は決め打ちで全部の(リンクに使用されるなど)関数っぽいシンボルに interwork のためのスタブを生成していたのが、2.22 以降、より効率的なコードを生成するためにアルゴリズムが変わった、などの事情があったのでしょうか。(ちゃんと調べたわけでは無いので、想像です。)

ちなみに U-Boot でも、thumb をサポートする際に、以下のような patch が投げられていて、ちゃんと理由が説明されていました。参考になります。%function はアセンブラではなく、リンカに対する情報とのこと。
[U-Boot] [PATCH 2/4] arm: add %function attribute to assembly functions
This is done using the following directive preceding
each function definition:

.type , %function

This marks the symbol as a function in the object
header which in turn helps the linker in some cases.

In particular this was found needed for resolving ARM/Thumb
calls correctly in a build with Thumb interworking enabled.

This solves the following problem I had reported earlier:

"When U-Boot/SPL is built using the Thumb instruction set the
toolchain has a  potential issue with weakly linked symbols.
If a function has a weakly linked default implementation in C
and a real implementation in assembly GCC is confused about the
instruction set of the assembly implementation. As a result
the assembly function that is built in ARM is executed as
if it is Thumb. This results in a crash"


トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード