リンカーとライブラリ

再配置セクション

再配置は、シンボル参照をシンボル定義に関連付ける処理です。たとえば、プログラムが関数を呼び出すとき、関連付けられている呼び出し命令は、実行時に適切な宛先アドレスに制御を渡さなければなりません。再配置可能ファイルには、セクション内容の変更方法を示す情報が存在しなければなりません。この情報により、実行可能オブジェクトファイルと共有オブジェクトファイルは、プロセスのプログラムイメージに関する正しい情報を保持できます。再配置エントリは、これらのデータを保持します。

再配置エントリは、次の構造体を持つことができます。sys/elf.h を参照してください。

typedef struct {
        Elf32_Addr      r_offset;
        Elf32_Word      r_info;
} Elf32_Rel;
 
typedef struct {
        Elf32_Addr      r_offset;
        Elf32_Word      r_info;
        Elf32_Sword     r_addend;
} Elf32_Rela;

typedef struct {
        Elf64_Addr      r_offset;
        Elf64_Xword     r_info;
} Elf64_Rel;
 
typedef struct {
        Elf64_Addr      r_offset;
        Elf64_Xword     r_info;
        Elf64_Sxword    r_addend;
} Elf64_Rela;
r_offset

このメンバーは、再配置処理を適用する位置を与えます。オブジェクトファイルが異なると、このメンバーの解釈が多少異なります。

再配置可能ファイルの場合、値はセクションのオフセットを示します。再配置セクション自身はファイルの別セクションの変更方法を示します。再配置オフセットは、2 番目のセクション内の領域を指定します。

実行可能ファイルまたは共有オブジェクトの場合、値は再配置の影響を受ける領域の仮想アドレスを示します。この情報により、再配置エントリは、実行時リンカーにとって、より意味のあるものになります。

関連するプログラムによるアクセスの効率を高めるため、メンバーの解釈はオブジェクトファイルによって異なりますが、再配置タイプの意味は同じになります。

r_info

このメンバーは、再配置が行われなければならないシンボルテーブルインデックスと、適用される再配置の種類を与えます。たとえば、呼び出し命令の再配置エントリは、呼び出される関数のシンボルテーブルインデックスを保持します。インデックスが STN_UNDEF (未定義シンボルインデックス) の場合、再配置はシンボル値として 0 を使用します。

再配置の種類はプロセッサに固有です。再配置エントリの再配置の種類またはシンボルテーブルインデックスは、それぞれ ELF32_R_TYPE または ELF32_R_SYM をエントリの r_info メンバーに適用した結果です。

#define ELF32_R_SYM(info)             ((info)>>8)
#define ELF32_R_TYPE(info)            ((unsigned char)(info))
#define ELF32_R_INFO(sym, type)       (((sym)<<8)+(unsigned char)(type))

#define ELF64_R_SYM(info)             ((info)>>32)
#define ELF64_R_TYPE(info)            ((Elf64_Word)(info))
#define ELF64_R_INFO(sym, type)       (((Elf64_Xword)(sym)<<32)+ \ 
                                        (Elf64_Xword)(type))

64 ビット SPARC Elf64_Rela 構造の場合、r_info フィールドはさらに 8 ビットの識別子と 24 ビットの付随的なデータに分割されます。既存の再配置タイプの場合、データフィールドはゼロになります。これに対し、新しい再配置タイプの場合には、データビットが使用される可能性があります。

#define ELF64_R_TYPE_DATA(info)       (((Elf64_Xword)(info)<<32)>>40)
#define ELF64_R_TYPE_ID(info)         (((Elf64_Xword)(info)<<56)>>56)
#define ELF64_R_TYPE_INFO(data, type) (((Elf64_Xword)(data)<<8)+ \ 
                                        (Elf64_Xword)(type))
r_addend

このメンバーは、再配置可能フィールドに格納される値の計算に使用される定数加数を指定します。

Rela エントリには、明示的加数が含まれます。Rel エントリには、変更される位置に暗黙の加数が存在します。32 ビット SPARC では、Elf32_Rela 再配置エントリのみを使用します。64 ビット SPARC および 64 ビット x86 では、 Elf64_Rela 再配置エントリのみを使用します。したがって、r_addend メンバーは再配置加数として機能します。x86 は、Elf32_Rel 再配置エントリのみを使用します。再配置対象のフィールドは、加数を保持します。すべての場合において、加数と計算された結果は同じバイト順序を使用します。

再配置セクションは、ほかに 2 つのセクションを参照することがあります。 1 つは sh_info セクションヘッダーエントリにより示されるシンボルテーブルで、もう 1 つは sh_link セクションヘッダーエントリにより示される変更対象のセクションです。「セクション」 に、各セクションの関係を示します。再配置オブジェクトに再配置セクションが存在するが、実行可能ファイルや共有オブジェクトが任意の場合は、sh_info エントリが必要です。再配置オフセットが存在すれば、再配置を実行できます。

再配置型 (プロセッサ固有)

再配置エントリには、次の図に示す命令およびデータフィールドの変更方法が記述されます。ビット番号は、下隅に示されています。

SPARC プラットフォームの場合、再配置エントリはバイト (byte8)、ハーフワード (half16) またはワードに適用されます。

32 ビットの再配置エントリ。

64 ビット SPARC と x64 では、再配置は拡張ワード (xword64) にも適用されます。

64 ビットの再配置エントリ。

x86 の場合、再配置エントリはワード (word32) に適用されます。

x86 再配置エントリ

word32 は、任意バイト整列が存在する 4 バイトを占める 32 ビットフィールドを指定します。これらの値は、x86 アーキテクチャーにおけるほかのワード値と同じバイト順序を使用します。

x86 再配置エントリ

いずれの場合でも r_offset 値は、影響が与えられる領域の先頭バイトのオフセットまたは仮想アドレスを指定します。再配置タイプは、変更されるビットと、これらのビットの値の計算方法を指定します。

次の再配置型の計算では、操作により、再配置可能ファイルが実行可能ファイルまたは共有オブジェクトファイルに変換されることが仮定されています。概念上、リンカーは 1 つまたは複数の再配置可能ファイルを併合して出力します。リンカーは、まず入力ファイルの結合/配置方法を決めます。次に、シンボルの値を更新し、再配置を実行します。実行可能オブジェクトファイルと共有オブジェクトファイルに適用される再配置は類似しており、同じ結果を実現します。このセクションの表では、次の表記が使用されています。

A

再配置可能フィールドの値を計算するために使用される加数。

B

実行時に共有オブジェクトがメモリーに読み込まれるベースアドレス。一般的に、共有オブジェクトファイルは、ベース仮想アドレス 0 で作成されます。ただし、共有オブジェクトの実行アドレスは異なります。「プログラムヘッダー」を参照してください。

G

実行時に再配置エントリのシンボルのアドレスが存在する大域オフセットテーブルへのオフセット。「大域オフセットテーブル (プロセッサ固有)」を参照してください。

GOT

大域オフセットテーブルのアドレス。「大域オフセットテーブル (プロセッサ固有)」を参照してください。

L

シンボルに対するプロシージャーのリンクテーブルエントリのセクションオフセットまたはアドレス。「プロシージャーのリンクテーブル (プロセッサ固有)」を参照してください。

P

再配置される領域のセクションオフセットまたはアドレス (r_offset を使用して計算)。

S

インデックスが再配置エントリ内に存在するシンボルの値。

Z

インデックスが再配置エントリ内に存在するシンボルのサイズ。

SPARC: 再配置型

次の表に示すフィールド名は、再配置型がオーバーフローを検査するかどうかを通知します。計算される再配置値は意図したフィールドより大きい場合があり、再配置型によっては値の適合を検証 (V) したり結果を切り捨てたり (T) することがあります。たとえば、V-simm13 は、計算された値が simm13 フィールドの外部に 0 以外の有意ビットを持つことがないことを意味します。

表 7–13 SPARC: ELF 再配置型

名前 

値 

フィールド 

計算 

R_SPARC_NONE

0

None

None

R_SPARC_8

1

V-byte8

S + A

R_SPARC_16

2

V-half16

S + A

R_SPARC_32

3

V-word32

S + A

R_SPARC_DISP8

4

V-byte8

S + A - P

R_SPARC_DISP16

5

V-half16

S + A - P

R_SPARC_DISP32

6

V-disp32

S + A - P

R_SPARC_WDISP30

7

V-disp30

(S + A - P) >> 2

R_SPARC_WDISP22

8

V-disp22

(S + A - P) >> 2

R_SPARC_HI22

9

T-imm22

(S + A) >> 10

R_SPARC_22

10

V-imm22

S + A

R_SPARC_13

11

V-simm13

S + A

R_SPARC_LO10

12

T-simm13

(S + A) & 0x3ff

R_SPARC_GOT10

13

T-simm13

G & 0x3ff

R_SPARC_GOT13

14

V-simm13

G

R_SPARC_GOT22

15

T-simm22

G >> 10

R_SPARC_PC10

16

T-simm13

(S + A - P) & 0x3ff

R_SPARC_PC22

17

V-disp22

(S + A - P) >> 10

R_SPARC_WPLT30

18

V-disp30

(L + A - P) >> 2

R_SPARC_COPY

19

None

この表のあとの説明を参照してください。 

R_SPARC_GLOB_DAT

20

V-word32

S + A

R_SPARC_JMP_SLOT

21

None

この表のあとの説明を参照してください。 

R_SPARC_RELATIVE

22

V-word32

B + A

R_SPARC_UA32

23

V-word32

S + A

R_SPARC_PLT32

24

V-word32

L + A

R_SPARC_HIPLT22

25

T-imm22

(L + A) >> 10

R_SPARC_LOPLT10

26

T-simm13

(L + A) & 0x3ff

R_SPARC_PCPLT32

27

V-word32

L + A - P

R_SPARC_PCPLT22

28

V-disp22

(L + A - P) >> 10

R_SPARC_PCPLT10

29

V-simm13

(L + A - P) & 0x3ff

R_SPARC_10

30

V-simm10

S + A

R_SPARC_11

31

V-simm11

S + A

R_SPARC_HH22

34

V-imm22

(S + A) >> 42

R_SPARC_HM10

35

T-simm13

((S + A) >> 32) & 0x3ff

R_SPARC_LM22

36

T-imm22

(S + A) >> 10

R_SPARC_PC_HH22

37

V-imm22

(S + A - P) >> 42

R_SPARC_PC_HM10

38

T-simm13

((S + A - P) >> 32) & 0x3ff

R_SPARC_PC_LM22

39

T-imm22

(S + A - P) >> 10

R_SPARC_WDISP16

40

V-d2/disp14

(S + A - P) >> 2

R_SPARC_WDISP19

41

V-disp19

(S + A - P) >> 2

.R_SPARC_7

43

V-imm7

S + A

R_SPARC_5

44

V-imm5

S + A

R_SPARC_6

45

V-imm6

S + A

R_SPARC_HIX22

48

V-imm22

((S + A) ^ 0xffffffffffffffff) >> 10

R_SPARC_LOX10

49

T-simm13

((S + A) & 0x3ff) | 0x1c00

R_SPARC_H44

50

V-imm22

(S + A) >> 22

R_SPARC_M44

51

T-imm10

((S + A) >> 12) & 0x3ff

R_SPARC_L44

52

T-imm13

(S + A) & 0xfff

R_SPARC_REGISTER

53

V-word32

S + A

R_SPARC_UA16

55

V-half16

S + A

R_SPARC_GOTDATA_HIX22

80

T-imm22

((S + A - GOT) >> 10) ^ ((S + A - GOT) >> 31)

R_SPARC_GOTDATA_LOX10

81

T-imm13

((S + A - GOT) & 0x3ff) | (((S + A - GOT) >> 31) & 0x1c00)

R_SPARC_GOTDATA_OP_HIX22

82

T-imm22

(G >> 10) ^ (G >> 31)

R_SPARC_GOTDATA_OP_LOX10

83

T-imm13

(G & 0x3ff) | ((G >> 31) & 0x1c00)

R_SPARC_GOTDATA_OP

84

Word32

この表のあとの説明を参照してください。 


注 –

スレッド固有領域の参照に使用できる再配置はほかにも存在します。これらの再配置については、第 8 章スレッド固有領域 (TLS)で説明しています。


いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。

R_SPARC_GOT10

R_SPARC_LO10 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT10 は、大域オフセットテーブルの作成をリンカーに指示します。

R_SPARC_GOT13

R_SPARC_13 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT13 は、大域オフセットテーブルの作成をリンカーに指示します。

R_SPARC_GOT22

R_SPARC_22 に似ていますが、シンボルの GOT エントリのアドレスを参照する点が異なります。また、 R_SPARC_GOT22 は、大域オフセットテーブルの作成をリンカーに指示します。

R_SPARC_WPLT30

R_SPARC_WDISP30 に似ていますが、シンボルのプロシージャーリンクテーブルエントリのアドレスを参照する点が異なります。また、R_SPARC_WPLT30 は、プロシージャーのリンクテーブル作成をリンカーに指示します。

R_SPARC_COPY

リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセットメンバーは、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。「コピー再配置」を参照してください。

R_SPARC_GLOB_DAT

R_SPARC_32 に似ていますが、再配置は GOT エントリを指定されたシンボルのアドレスに設定する点が異なります。この特殊な再配置型を使うと、シンボルと GOT エントリの対応付けを判定できます。

R_SPARC_JMP_SLOT

リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセットメンバーは、プロシージャーのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャーのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。

R_SPARC_RELATIVE

リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセットメンバーは、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して値 0 を指定する必要があります。

R_SPARC_UA32

R_SPARC_32 に似ていますが、整列されていないワードを参照する点が異なります。再配置されるワードは、任意整列が存在する 4 つの別個のバイトとして処理されなければなりません (アーキテクチャーの要求に従って整列されるワードとしては処理されません)。

R_SPARC_LM22

R_SPARC_HI22 に似ていますが、妥当性検査ではなく切り捨てを行う点が異なります。

R_SPARC_PC_LM22

R_SPARC_PC22に似ていますが、妥当性検査ではなく切り捨てを行う点が異なります。

R_SPARC_HIX22

64 ビットアドレス空間の最上位 4G バイトに限定される実行可能ファイルに対して R_SPARC_LOX10 とともに使用されます。R_SPARC_HI22 に似ていますが、リンク値の 1 の補数を与えます。

R_SPARC_LOX10

R_SPARC_HIX22 とともに使用されます。R_SPARC_LO10 に似ていますが、必ずリンク値のビット 10 からビット 12 までを設定します。

R_SPARC_L44

再配置型 R_SPARC_H44 および R_SPARC_M44 とともに使用され、44 ビット絶対アドレス指定モデルを生成します。

R_SPARC_REGISTER

レジスタシンボルの初期化に使用されます。この再配置型のオフセットメンバーには、初期化されるレジスタ番号が存在します。このレジスタに対応するレジスタシンボルが必要です。このシンボルの種類は SHN_ABS です。

R_SPARC_GOTDATA_OP_HIX22R_SPARC_GOTDATA_OP_LOX10R_SPARC_GOTDATA_OP

これらの再配置はコード変換に対応したものです。

64 ビット SPARC: 再配置型

再配置計算に使用される次の表記は、64 ビット SPARC 固有のものです。

O

再配置可能フィールドの値を計算するために使用される二次的な加数。この加数は、ELF64_R_TYPE_DATA マクロを適用することにより r_info フィールドから抽出されます。

次の表に示す再配置型は、32 ビット SPARC 用に定義された再配置型を拡張または変 更します。「SPARC: 再配置型」を参照してください。

表 7–14 64 ビット SPARC: ELF 再配置型

名前 

値 

フィールド 

計算 

R_SPARC_HI22

9

V-imm22

(S + A) >> 10

R_SPARC_GLOB_DAT

20

V-xword64

S + A

R_SPARC_RELATIVE

22

V-xword64

B + A

R_SPARC_64

32

V-xword64

S + A

R_SPARC_OLO10

33

V-simm13

((S + A) & 0x3ff) + O

R_SPARC_DISP64

46

V-xword64

S + A - P

R_SPARC_PLT64

47

V-xword64

L + A

R_SPARC_REGISTER

53

V-xword64

S + A

R_SPARC_UA64

54

V-xword64

S + A

R_SPARC_H34

85

V-imm22

(S + A) >> 12

次の再配置型には、単純な計算を超えたセマンティクスが存在します。

R_SPARC_OLO10

R_SPARC_LO10 に似ていますが、符号付き13 ビット即値フィールドを十分に使用するために余分なオフセットが追加される点が異なります。

32 ビット x86: 再配置型

次の表に、32 ビット x86 用に定義された再配置を示します。

表 7–15 32 ビット x86: ELF 再配置型

名前 

値 

フィールド 

計算 

R_386_NONE

0

None

None

R_386_32

1

word32

S + A

R_386_PC32

2

word32

S + A - P

R_386_GOT32

3

word32

G + A

R_386_PLT32

4

word32

L + A - P

R_386_COPY

5

None

この表のあとの説明を参照してください。 

R_386_GLOB_DAT

6

word32

S

R_386_JMP_SLOT

7

word32

S

R_386_RELATIVE

8

word32

B + A

R_386_GOTOFF

9

word32

S + A - GOT

R_386_GOTPC

10

word32

GOT + A - P

R_386_32PLT

11

word32

L + A

R_386_16

20

word16

S + A

R_386_PC16

21

word16

S + A - P

R_386_8

22

word8

S + A

R_386_PC8

23

word8

S + A - P


注 –

スレッド固有領域の参照に使用できる再配置はほかにも存在します。これらの再配置については、第 8 章スレッド固有領域 (TLS)で説明しています。


いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。

R_386_GOT32

GOT のベースからシンボルの GOT エントリまでの距離を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。

R_386_PLT32

シンボルのプロシージャーのリンクテーブルエントリのアドレスを計算し、かつプロシージャーのリンクテーブルを作成するようにリンカーに指示します。

R_386_COPY

リンカーは、この再配置型を作成して、動的実行可能ファイルが読み取り専用のテキストセグメントを保持できるようにします。この再配置型のオフセットメンバーは、書き込み可能セグメントの位置を参照します。シンボルテーブルインデックスは、現オブジェクトファイルと共有オブジェクトの両方に存在する必要があるシンボルを指定します。実行時、実行時リンカーは共有オブジェクトのシンボルに関連付けられているデータを、オフセットで指定されている位置にコピーします。「コピー再配置」を参照してください。

R_386_GLOB_DAT

GOT エントリを、指定されたシンボルのアドレスに設定します。この特殊な再配置型を使うと、シンボルと GOT エントリの対応付けを判定できます。

R_386_JMP_SLOT

リンカーは、動的オブジェクトが遅延結合を提供できるようにするため、この再配置型を作成します。この再配置型のオフセットメンバーは、プロシージャーのリンクテーブルエントリの位置を与えます。実行時リンカーは、プロシージャーのリンクテーブルエントリを変更して指定シンボルアドレスに制御を渡します。

R_386_RELATIVE

リンカーは、動的オブジェクト用にこの再配置型を作成します。この再配置型のオフセットメンバーは、相対アドレスを表す値が存在する、共有オブジェクト内の位置を与えます。実行時リンカーは共有オブジェクトが読み込まれる仮想アドレスに相対アドレスを加算することで、対応する仮想アドレスを計算します。この型に対する再配置エントリは、シンボルテーブルインデックスに対して値 0 を指定する必要があります。

R_386_GOTOFF

シンボルの値と GOT のアドレスの差を計算します。この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。

R_386_GOTPC

R_386_PC32 に似ていますが、計算を行う際に GOT のアドレスを使用する点が異なります。この再配置で参照されるシンボルは、通常 _GLOBAL_OFFSET_TABLE_ です。 この再配置型はまた、大域オフセットテーブルを作成するようにリンカーに指示します。

x64: 再配置型

次の表に、x64 用に定義された再配置を示します。

表 7–16 x64: ELF 再配置型

名前 

値 

フィールド 

計算 

R_AMD64_NONE

0

None

None

R_AMD64_64

1

word64

S + A

R_AMD64_PC32

2

word32

S + A - P

R_AMD64_GOT32

3

word32

G + A

R_AMD64_PLT32

4

word32

L + A - P

R_AMD64_COPY

5

None

この表のあとの説明を参照してください。 

R_AMD64_GLOB_DAT

6

word64

S

R_AMD64_JUMP_SLOT

7

word64

S

R_AMD64_RELATIVE

8

word64

B + A

R_AMD64_GOTPCREL

9

word32

G + GOT + A - P

R_AMD64_32

10

word32

S + A

R_AMD64_32S

11

word32

S + A

R_AMD64_16

12

word16

S + A

R_AMD64_PC16

13

word16

S + A - P

R_AMD64_8

14

word8

S + A

R_AMD64_PC8

15

word8

S + A - P

R_AMD64_PC64

24

word64

S + A - P

R_AMD64_GOTOFF64

25

word64

S + A - GOT

R_AMD64_GOTPC32

26

word32

GOT + A + P


注 –

スレッド固有領域の参照に使用できる再配置はほかにも存在します。これらの再配置については、第 8 章スレッド固有領域 (TLS)で説明しています。


これらの再配置型のほとんどの特別なセマンティクスは、x86 で使用されているものと同じです。いくつかの再配置型には、単純な計算を超えたセマンティクスが存在します。

R_AMD64_GOTPCREL

この再配置のセマンティクスは R_AMD64_GOT32 または等しい R_386_GOTPC 再配置と異なります。x64 アーキテクチャーは、命令ポインタに対して相対的なアドレス指定モードを提供します。したがって、アドレスは 1 つの命令で GOT から読み込むことができます。

R_AMD64_GOTPCREL 再配置の計算は、シンボルのアドレスを指定した GOT 内の位置と再配置を適用する位置の間の差を提供します。

R_AMD64_32

計算値は 32 ビットに切り捨てられます。リンカーは、再配置のために生成された値が元の 64 ビット値にゼロ拡張されていることを確認します。

R_AMD64_32S

計算値は 32 ビットに切り捨てられます。リンカーは、再配置のために生成された値が元の 64 ビット値に符号拡張されていることを確認します。

R_AMD64_8R_AMD64_16R_AMD64_PC16R_AMD64_PC8

これらの再配置は x64 ABI には準拠していませんが、文書化するためにここに追加しておきます。R_AMD64_8 再配置は、計算値を 8 ビットに切り詰めます。R_AMD64_16 再配置は、計算値を 16 ビットに切り詰めます。