🧶

Linker ScriptのSORTについて調べる

2020/10/28に公開

はじめに

リンカスクリプトを見てると、たまにSORTとかかれているところが見つかります。
例えば以下。

cortexm_base.ld

// cpu/cortexm_common/ldscripts/cortexm_base.ld
/* Section Definitions */
SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        _sfixed = .;
        _isr_vectors = DEFINED(_isr_vectors) ? _isr_vectors : . ;
        KEEP(*(SORT(.vectors*)))  // <-- ここ

何かをソートしているとは思うのですが、よくわかっていなかったので調べてみました。

Document

以下の記載がある。

ld document:SORT

Normally, the linker will place files and sections matched by 
wildcards in the order in which they are seen during the link. 
You can change this by using the SORT_BY_NAME keyword, which 
appears before a wildcard pattern in parentheses (e.g., SORT_BY_NAME(.text*)). 
When the SORT_BY_NAME keyword is used, the linker will sort the files or 
sections into ascending order by name before placing them in the output file.

(省略)

SORT is an alias for SORT_BY_NAME.

動作確認(テストの実行)

Document記載の通りなのでしょうが、ちょっと動作も確認したいところ。
コードを確認したら以下のようなものがありました。

ld/testsuite/ld-scripts/sort_b_n.d

#source: sort_b_n.s
#ld: -T sort_b_n.t
#name: SORT_BY_NAME
#nm: -n

#...
0[0-9a-f]* t text
#...
0[0-9a-f]* t text1
#...
0[0-9a-f]* t text2
#...
0[0-9a-f]* t text3
#pass

testsuiteというフォルダに入っているのでテストコードなのでしょう。
このテストの実行方法を調べたら、似たような事を質問している人がいました。
How to build and run the GNU GAS assembler test suite?

DejaGnu が必要ということなので
インストールしてテストの実行をしてみる。
SORTについてのテストも動いているっぽい。

$ sudo apt install dejagnu
$ mkdir build
$ cd build
$ ../configure
$ make
$ cd ld
$ make check
make  check-recursive
(省略)

		=== ld tests ===

Schedule of variations:
    unix

Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /home/<USERNAME>/binutils-gdb/ld/testsuite/config/default.exp as tool-and-target-specific interface file.
(省略)
Running /home/<USERNAME>/binutils-gdb/ld/testsuite/ld-scripts/sort.exp ...
(省略)

		=== ld Summary ===

# of expected passes		2570
# of expected failures		57
# of untested testcases		1
# of unsupported tests		23
./ld-new 2.35

動作確認(link後のバイナリ確認)

テストは動かせたので、SORTの有無で出力されるバイナリにどのような違いがあるかを
確認してみる。

ld/testsuite/ld-scripts/sort_b_n.d で使用しているasmコードを適当なディレクトリに用意。
ファイル名はsample.sとした。

	.section .text2
text2:
	.long 0
	.section .text3
text3:
	.long 0
	.section .text1
text1:
	.long 0
	.text
text:
	.long 0

linker scriptは以下の2つを用意。

// sample.ld
SECTIONS
{
  .text : {*(SORT_BY_NAME(.text*))}
  /DISCARD/ : { *(.*) }
}
// sample2.ld
// SORT_BY_NAMEを削除
SECTIONS
{
  .text : {*(.text*)}
  /DISCARD/ : { *(.*) }
}

アセンブル、リンクをしてobjdumpで
disassembleの結果を出力。
(ARM用のgccを使用)

$ arm-none-eabi-as -o sample.o sample.s 

# それぞれのlinker scriptを指定してlink
$ arm-none-eabi-ld -T sample.ld sample.o -o sample
$ arm-none-eabi-ld -T sample2.ld sample.o -o sample2

# objdumpの結果を出力
$ arm-none-eabi-objdump -D sample > objdump-sample.txt
$ arm-none-eabi-objdump -D sample2 > objdump-sample2.txt

結果を比較。

$ diff -y --left-column objdump-sample.txt objdump-sample2.txt
							      (
sample:     file format elf32-littlearm			      |	sample2:     file format elf32-littlearm
							      (
							      (
Disassembly of section .text:				      (
							      (
00000000 <text>:					      (
   0:	00000000 	andeq	r0, r0, r0		      (
							      (
00000004 <text1>:					      |	00000004 <text2>:
   4:	00000000 	andeq	r0, r0, r0		      (
							      (
00000008 <text2>:					      |	00000008 <text3>:
   8:	00000000 	andeq	r0, r0, r0		      (
							      (
0000000c <text3>:					      |	0000000c <text1>:
   c:	00000000 	andeq	r0, r0, r0		      (

テキストだとちょっと見にくいので、VS Code上で比較した結果。
SORTをつけた場合は、text,text1,text2,text3の順番に並んでいる(下記画像左側)。

Discussion