LLVM 拡張機能¶
はじめに¶
このドキュメントでは、LLVM が互換性を目指しているツールおよびフォーマットの拡張機能について説明します。
汎用アセンブリ構文¶
C99 形式の16進浮動小数点定数¶
LLVM のアセンブラでは、必要に応じて、浮動小数点定数を10進数ではなく C99 の16進数形式で記述できます。
.section .data
.float 0x1c2.2ap3
マシン固有のアセンブリ構文¶
X86/COFF 依存¶
再配置¶
以下の追加の再配置タイプがサポートされています。
**@IMGREL** (AT&T 構文のみ) は、COFF 再配置タイプ IMAGE_REL_I386_DIR32NB
(32 ビット) または IMAGE_REL_AMD64_ADDR32NB
(64 ビット) に対応する、イメージ相対再配置を生成します。
.text
fun:
mov foo@IMGREL(%ebx, %ecx, 4), %eax
.section .pdata
.long fun@IMGREL
.long (fun@imgrel + 0x3F)
.long $unwind$fun@imgrel
**.secrel32** は、COFF 再配置タイプ IMAGE_REL_I386_SECREL
(32 ビット) または IMAGE_REL_AMD64_SECREL
(64 ビット) に対応する再配置を生成します。
**.secidx** 再配置は、ターゲットを含むセクションのインデックスを生成します。COFF 再配置タイプ IMAGE_REL_I386_SECTION
(32 ビット) または IMAGE_REL_AMD64_SECTION
(64 ビット) に対応します。
.section .debug$S,"rn"
.long 4
.long 242
.long 40
.secrel32 _function_name + 0
.secidx _function_name
...
.linkonce
ディレクティブ¶
構文
.linkonce [ comdat タイプ ]
サポートされている COMDAT タイプ
discard
同じ COMDAT シンボルを持つ重複セクションを破棄します。タイプが指定されていない場合、これがデフォルトです。
one_only
シンボルが複数回定義されている場合、リンカはエラーを発行します。
same_size
重複は破棄されますが、サイズが異なるものがある場合、リンカはエラーを発行します。
same_contents
重複は破棄されますが、重複の内容が完全に同じでない場合、リンカはエラーを発行します。
largest
重複の中から最大のセクションをリンクします。
newest
重複の中から最新のセクションをリンクします。
.section .text$foo
.linkonce
...
.section
ディレクティブ¶
MC は、.linkonce
の情報を .section
の最後に渡すことをサポートしています。たとえば、次の 2 つのコードは同等です。
.section secName, "dr", discard, "Symbol1"
.globl Symbol1
Symbol1:
.long 1
.section secName, "dr"
.linkonce discard
.globl Symbol1
Symbol1:
.long 1
結合された形式では、COMDAT シンボルが明示的であることに注意してください。この拡張機能は、異なる COMDAT に同じ名前の複数のセクションをサポートするために存在します。
.section secName, "dr", discard, "Symbol1"
.globl Symbol1
Symbol1:
.long 1
.section secName, "dr", discard, "Symbol2"
.globl Symbol2
Symbol2:
.long 1
.linkonce
で許可されているタイプに加えて、.section
は associative
も受け入れます。これは、特定の他の COMDAT セクションがリンクされている場合に、そのセクションがリンクされることを意味します。この他のセクションは、このディレクティブの comdat シンボルによって示されます。関連付けられたセクションで定義されている任意のシンボルにすることができますが、通常は関連付けられたセクションの comdat です。
関連付けられたセクションには、次の制限が適用されます。
COMDAT セクションである必要があります。
別の連想 COMDAT セクションにすることはできません。
次の例では、シンボル sym
は .foo
の comdat シンボルであり、.bar
は .foo
に関連付けられています。
.section .foo,"bw",discard, "sym"
.section .bar,"rd",associative, "sym"
MC は、COFF .section
ディレクティブでこれらのフラグをサポートしています。
b
: BSS セクション (IMAGE_SCN_CNT_INITIALIZED_DATA
)
d
: データセクション (IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
n
: セクションはロードされない (IMAGE_SCN_LNK_REMOVE
)
r
: 読み取り専用
s
: 共有セクション
w
: 書き込み可能
x
: 実行可能セクション
y
: 読み取り不可
D
: 破棄可能 (IMAGE_SCN_MEM_DISCARDABLE
)
これらのフラグはすべて gas と互換性があります。ただし、gnu as がサポートしていない D
フラグは例外です。gas との互換性のために、「.debug」で始まる名前のセクションは暗黙的に破棄可能です。
ARM64/COFF 依存¶
再配置¶
以下の追加のシンボルバリアントがサポートされています。
**:secrel_lo12:** COFF 再配置タイプ IMAGE_REL_ARM64_SECREL_LOW12A
または IMAGE_REL_ARM64_SECREL_LOW12L
に対応する再配置を生成します。
**:secrel_hi12:** COFF 再配置タイプ IMAGE_REL_ARM64_SECREL_HIGH12A
に対応する再配置を生成します。
add x0, x0, :secrel_hi12:symbol
ldr x0, [x0, :secrel_lo12:symbol]
add x1, x1, :secrel_hi12:symbol
add x1, x1, :secrel_lo12:symbol
...
ELF 依存¶
.section
ディレクティブ¶
同じ名前と comdat を持つ複数のセクションを作成できるように、.section
ディレクティブの最後に一意の番号を追加することができます。たとえば、次のコードは .text
という名前の 2 つのセクションを作成します。
.section .text,"ax",@progbits,unique,1
nop
.section .text,"ax",@progbits,unique,2
nop
一意の番号は、結果のオブジェクトにはまったく存在しません。アセンブラでセクションを区別するためにのみ使用されます。
'o' フラグは SHF_LINK_ORDER にマップされます。存在する場合、.sh_link に配置されるセクションを識別するシンボルを指定する必要があります。
.section .foo,"a",@progbits
.Ltmp:
.section .bar,"ao",@progbits,.Ltmp
これは、単に次のように記述するのと同じです。
.section .foo,"a",@progbits
.section .bar,"ao",@progbits,.foo
.linker-options
セクション (リンカオプション)¶
フロントエンドからリンカにリンカオプションを渡せるようにするために、タイプ SHT_LLVM_LINKER_OPTIONS
の特別なセクション (通常は .linker-options
という名前ですが、タイプによって識別されるため、名前は重要ではありません) があります。このセクションの内容は、リンカが考慮するためのディレクティブの単純なペアワイズエンコーディングです。文字列は、標準のヌル終端 UTF-8 文字列としてエンコードされます。リンカが値を取得するためにオブジェクトファイルをトラバースするのを避けるために、インラインで出力されます。リンカは、オプションを無視し、代わりに要求されたオプションが受け入れられなかったという警告/エラーをユーザーに提供することを許可されています。
セクションのタイプは SHT_LLVM_LINKER_OPTIONS
で、SHF_EXCLUDE
フラグが設定されているため、この機能をサポートしていないリンカではセクションが不透明として扱われ、最終的なリンク済みバイナリに出力されません。
これは、次の raw アセンブリと同等です。
.section ".linker-options","e",@llvm_linker_options
.asciz "option 1"
.asciz "value 1"
.asciz "option 2"
.asciz "value 2"
以下のディレクティブが指定されています。
lib
パラメータは、リンク対象のライブラリを識別します。ライブラリは、デフォルトと指定されたライブラリ検索パス (この時点までに指定されたもの) で検索されます。
libpath
パラメータは、このオプションを含めた後、ライブラリを検索する際に考慮される追加のライブラリ検索パスを識別します。
SHT_LLVM_DEPENDENT_LIBRARIES
セクション (依存ライブラリ)¶
このセクションには、リンカによってリンクに追加されるライブラリを指定する文字列が含まれています。
このセクションはリンカによって消費され、出力には書き込まれません。
文字列は、標準のヌル終端 UTF-8 文字列としてエンコードされます。
例えば
.section ".deplibs","MS",@llvm_dependent_libraries,1
.asciz "library specifier 1"
.asciz "library specifier 2"
ライブラリ指定子の解釈は、使用するリンカによって定義されます。
SHT_LLVM_CALL_GRAPH_PROFILE
セクション (コールグラフプロファイル)¶
このセクションは、セクションの配置を最適化するために使用できるコールグラフプロファイルをリンカに渡すために使用されます。これは、(from シンボル, to シンボル, 重み) のタプルのシーケンスを含みます。
これは、タイプ SHT_LLVM_CALL_GRAPH_PROFILE
(0x6fff4c02) を持ち、SHF_EXCLUDE
フラグが設定され、sh_link
メンバーは関連付けられたシンボルテーブルのセクションヘッダーインデックスを保持し、sh_entsize
は 16 である必要があります。名前は .llvm.call-graph-profile
である必要があります。
セクションの内容は、Elf_CGProfile
エントリのシーケンスです。
typedef struct {
Elf_Word cgp_from;
Elf_Word cgp_to;
Elf_Xword cgp_weight;
} Elf_CGProfile;
- cgp_from
エッジのソースのシンボルインデックス。
- cgp_to
エッジのデスティネーションのシンボルインデックス。
- cgp_weight
エッジの重み。
これは、アセンブリでは次のように表されます。
.cg_profile from, to, 42
.cg_profile
ディレクティブはファイルの最後に処理されます。from
または to
が未定義の一時シンボルである場合、エラーになります。いずれかのシンボルが一時シンボルである場合、代わりにセクションシンボルが使用されます。いずれかのシンボルが未定義の場合、そのシンボルはファイルの最後に .weak symbol
が記述されたかのように定義されます。これにより、シンボルがシンボルテーブルに確実に表示されます。
SHT_LLVM_ADDRSIG
セクション (アドレス有意テーブル)¶
このセクションは、シンボルをアドレス有意としてマークするために使用されます。つまり、シンボルのアドレスが比較で使用されるか、翻訳単位の外部にリークします。これは、LLVM 属性 unnamed_addr
および local_unnamed_addr
が存在しないことと同じ意味です。
どのオブジェクトファイルでもアドレス有意としてマークされていないシンボルによって参照されるセクションは、C および C++ 言語標準によって提供されるアドレスの固有性保証を損なうことなく、リンカによって安全にマージできます。
セクションの内容は、アドレス有意シンボルのシンボルテーブルインデックスを参照する ULEB128 エンコード整数のシーケンスです。
2 つの関連するアセンブリディレクティブがあります
.addrsig
これは、アセンブラにアドレス有意テーブルを出力するように指示します。このディレクティブがない場合、すべてのシンボルはアドレス有意と見なされます。
.addrsig_sym sym
sym
がファイル内の他の場所で参照または定義されていない場合、このディレクティブは何もしません。それ以外の場合、sym
をアドレス有意としてマークします。
SHT_LLVM_SYMPART
セクション (シンボルパーティション仕様)¶
このセクションは、シンボルに所属するパーティションをマークするために使用されます。.llvm_sympart
セクションは、パーティションの名前を指定するヌル終端文字列と、パーティションに属するシンボルを参照する再配置で構成されます。次のように構築できます
.section ".llvm_sympart","",@llvm_sympart
.asciz "libpartition.so"
.word symbol_in_partition
SHT_LLVM_BB_ADDR_MAP
セクション (基本ブロックアドレスマップ)¶
このセクションには、基本ブロックのバイナリ アドレスと、その他の関連メタデータが格納されます。この情報は、バイナリ プロファイル (perf プロファイルなど) をマシンの基本ブロックに直接マッピングするために使用できます。このセクションは -basic-block-sections=labels
で出力され、すべての関数に BB アドレス マップ テーブルが含まれます。
SHT_LLVM_BB_ADDR_MAP
タイプは、古いコンパイラによって生成された古いバージョンの BB アドレス マップの読み取りを可能にする後方互換性を提供します。各関数エントリは、使用するエンコーディングバージョンを指定するバージョンバイトで始まります。現在、次のバージョン管理スキームがサポートされています。
バージョン 1 (最新): 基本ブロックアドレスオフセットは、前のブロックの終わりからの相対値として計算されます。
例
.section ".llvm_bb_addr_map","",@llvm_bb_addr_map
.byte 1 # version number
.byte 0 # feature byte (reserved for future use)
.quad .Lfunc_begin0 # address of the function
.byte 2 # number of basic blocks
# BB record for BB_0
.uleb128 .Lfunc_beign0-.Lfunc_begin0 # BB_0 offset relative to function entry (always zero)
.uleb128 .LBB_END0_0-.Lfunc_begin0 # BB_0 size
.byte x # BB_0 metadata
# BB record for BB_1
.uleb128 .LBB0_1-.LBB_END0_0 # BB_1 offset relative to the end of last block (BB_0).
.uleb128 .LBB_END0_1-.LBB0_1 # BB_1 size
.byte y # BB_1 metadata
バージョン 0: 基本ブロックアドレスオフセットは、関数アドレスからの相対値として計算されます。これは、バージョン管理されていない SHT_LLVM_BB_ADDR_MAP_V0
セクションタイプを使用し、バージョンフィールドがゼロの SHT_LLVM_BB_ADDR_MAP
を使用することと意味的に同等です。
例
.section ".llvm_bb_addr_map","",@llvm_bb_addr_map_v0
.quad .Lfunc_begin0 # address of the function
.byte 2 # number of basic blocks
# BB record for BB_0
.uleb128 .Lfunc_beign0-.Lfunc_begin0 # BB_0 offset relative to the function entry (always zero)
.uleb128 .LBB_END0_0-.Lfunc_begin0 # BB_0 size
.byte x # BB_0 metadata
# BB record for BB_1
.uleb128 .LBB0_1-.Lfunc_begin0 # BB_1 offset relative to the function entry
.uleb128 .LBB_END0_1-.LBB0_1 # BB_1 size
.byte y # BB_1 metadata
PGO 分析マップ¶
PGO 関連の分析データは、オプションの pgo-analysis-map
フラグを介して、SHT_LLVM_BB_ADDR_MAP
内の各関数の後に出力できます。現在サポートされている分析は、関数エントリカウント、基本ブロック頻度、および分岐確率です。
各分析は、feature バイトのビットによって有効または無効になります。現在、これらのビットは次のとおりです。
関数エントリカウント - PGO プロファイルから取得した関数が呼び出された回数。PGO が使用されなかった場合、またはプロファイルで関数が検出されなかった場合、これは常にゼロになります。
基本ブロック頻度 - MBFI 分析から取得した生のブロック頻度値としてエンコードされます。この値は、エントリブロックと比較した相対頻度をエンコードする整数です。詳細については、「llvm/Support/BlockFrequency.h」を参照してください。
分岐確率 - MBPI 分析から取得した分岐確率の生の分子としてエンコードされます。この値は、「llvm/Support/BranchProbability.h」で定義されている固定小数点数の分子です。これは、実行中にブロックが特定の後続ブロックに続く確率を示します。
この追加データには、バージョン 2 以降が必要です。これは、基本ブロックの後続はインデックスを知らないが、BB ID は知っているため必要です。
PGO データを含む BBAddrMap の例
.section ".llvm_bb_addr_map","",@llvm_bb_addr_map
.byte 2 # version number
.byte 7 # feature byte - PGO analyses enabled mask
.quad .Lfunc_begin0 # address of the function
.uleb128 4 # number of basic blocks
# BB record for BB_0
.uleb128 0 # BB_0 BB ID
.uleb128 .Lfunc_begin0-.Lfunc_begin0 # BB_0 offset relative to function entry (always zero)
.uleb128 .LBB_END0_0-.Lfunc_begin0 # BB_0 size
.byte 0x18 # BB_0 metadata (multiple successors)
# BB record for BB_1
.uleb128 1 # BB_1 BB ID
.uleb128 .LBB0_1-.LBB_END0_0 # BB_1 offset relative to the end of last block (BB_0).
.uleb128 .LBB_END0_1-.LBB0_1 # BB_1 size
.byte 0x0 # BB_1 metadata (two successors)
# BB record for BB_2
.uleb128 2 # BB_2 BB ID
.uleb128 .LBB0_2-.LBB_END1_0 # BB_2 offset relative to the end of last block (BB_1).
.uleb128 .LBB_END0_2-.LBB0_2 # BB_2 size
.byte 0x0 # BB_2 metadata (one successor)
# BB record for BB_3
.uleb128 3 # BB_3 BB ID
.uleb128 .LBB0_3-.LBB_END0_2 # BB_3 offset relative to the end of last block (BB_2).
.uleb128 .LBB_END0_3-.LBB0_3 # BB_3 size
.byte 0x0 # BB_3 metadata (zero successors)
# PGO Analysis Map
.uleb128 1000 # function entry count (only when enabled)
# PGO data record for BB_0
.uleb128 1000 # BB_0 basic block frequency (only when enabled)
.uleb128 3 # BB_0 successors count (only enabled with branch probabilities)
.uleb128 1 # BB_0 successor 1 BB ID (only enabled with branch probabilities)
.uleb128 0x22222222 # BB_0 successor 1 branch probability (only enabled with branch probabilities)
.uleb128 2 # BB_0 successor 2 BB ID (only enabled with branch probabilities)
.uleb128 0x33333333 # BB_0 successor 2 branch probability (only enabled with branch probabilities)
.uleb128 3 # BB_0 successor 3 BB ID (only enabled with branch probabilities)
.uleb128 0xaaaaaaaa # BB_0 successor 3 branch probability (only enabled with branch probabilities)
# PGO data record for BB_1
.uleb128 133 # BB_1 basic block frequency (only when enabled)
.uleb128 2 # BB_1 successors count (only enabled with branch probabilities)
.uleb128 2 # BB_1 successor 1 BB ID (only enabled with branch probabilities)
.uleb128 0x11111111 # BB_1 successor 1 branch probability (only enabled with branch probabilities)
.uleb128 3 # BB_1 successor 2 BB ID (only enabled with branch probabilities)
.uleb128 0x11111111 # BB_1 successor 2 branch probability (only enabled with branch probabilities)
# PGO data record for BB_2
.uleb128 18 # BB_2 basic block frequency (only when enabled)
.uleb128 1 # BB_2 successors count (only enabled with branch probabilities)
.uleb128 3 # BB_2 successor 1 BB ID (only enabled with branch probabilities)
.uleb128 0xffffffff # BB_2 successor 1 branch probability (only enabled with branch probabilities)
# PGO data record for BB_3
.uleb128 1000 # BB_3 basic block frequency (only when enabled)
.uleb128 0 # BB_3 successors count (only enabled with branch probabilities)
SHT_LLVM_OFFLOADING
セクション (オフロードデータ)¶
このセクションには、オフロードデバイスのリンクと実行を実行するために使用されるバイナリデータが格納され、ファットバイナリが作成されます。このセクションは、OpenMP や CUDA などのオフロード言語のコンパイル中に生成されます。データがデバイスリンカのみによって使用されることを目的としている場合は、SHF_EXCLUDE
フラグを使用して、最終的な実行可能ファイルまたは共有ライブラリから自動的に削除されるようにする必要があります。
このセクションに格納されているバイナリデータは、オフロードメタデータを格納するために使用されるカスタムバイナリ形式に準拠しています。この形式は、事実上、デバイスイメージを伴うメタデータを含む文字列テーブルです。
SHT_LLVM_LTO
セクション (ファット LTO 用の LLVM ビットコード)¶
このセクションには、リンク時に通常の LTO または ThinLTO を実行するために使用される LLVM ビットコードが格納されます。このセクションは、コンパイラがファット LTO を有効にしたときに生成されます。このセクションには SHF_EXCLUDE
フラグがあるため、最終的な実行可能ファイルまたは共有ライブラリから削除されます。
CodeView 依存¶
.cv_file
ディレクティブ¶
- 構文
.cv_file
ファイル番号 ファイル名 [ チェックサム ] [ チェックサムの種類 ]
.cv_func_id
ディレクティブ¶
.cv_loc
で使用できる関数 ID を導入します。
- 構文
.cv_func_id
関数 ID
.cv_inline_site_id
ディレクティブ¶
.cv_loc
で使用できる関数 ID を導入します。呼び出し元の行テーブルで使用するための inlined at
ソースロケーション情報を含みます。呼び出し元が実際の関数であるか、別のインライン化された呼び出しサイトであるかは関係ありません。
- 構文
.cv_inline_site_id
関数 IDwithin
関数inlined_at
ファイル番号 行番号 [ 列番号 ]
.cv_loc
ディレクティブ¶
最初の数字はファイル番号で、.file
ディレクティブで事前に割り当てられている必要があります。2 番目の数字は行番号で、オプションで 3 番目の数字は列位置です (指定されていない場合はゼロ)。残りのオプション項目は、.loc
サブディレクティブです。
- 構文
.cv_loc
関数ID ファイル番号 [ 行 ] [ 列 ] [ prologue_end ] [is_stmt
値 ]
.cv_linetable
ディレクティブ¶
- 構文
.cv_linetable
関数ID,
関数開始,
関数終了
.cv_inline_linetable
ディレクティブ¶
- 構文
.cv_inline_linetable
プライマリ関数ID,
ファイル番号 行 関数開始 関数終了
.cv_def_range
ディレクティブ¶
GapStart と GapEnd オプションは必要に応じて繰り返すことができます。
- 構文
.cv_def_range
範囲開始 範囲終了 [ Gap開始 Gap終了 ],
バイト数
.cv_stringtable
ディレクティブ¶
.cv_filechecksums
ディレクティブ¶
.cv_filechecksumoffset
ディレクティブ¶
- 構文
.cv_filechecksumoffset
ファイル番号
.cv_fpo_data
ディレクティブ¶
- 構文
.cv_fpo_data
procsym
ターゲット固有の動作¶
X86¶
再配置¶
@ABS8 は、8ビット即値形式を持つオペランドを持つ命令の即値オペランドとして現れるシンボルに適用できます。これにより、アセンブラは8ビット形式とシンボルに8ビット再配置(例:R_386_8
または R_X86_64_8
)を使用します。
例えば
cmpq $foo@ABS8, %rdi
これにより、アセンブラは、32ビット即値オペランドを取る cmpq $foo, %rdi
とは対照的に、64ビットに符号拡張される8ビット即値オペランドを取る64ビット cmpq
命令の形式を選択します。これは、8ビット比較である cmpb $foo, %dil
とも同じではありません。
@GOTPCREL_NORELAX は、@GOTPCREL
の代わりに使用して、アセンブラが緩和可能な R_X86_64[_REX]_GOTPCRELX
再配置ではなく、R_X86_64_GOTPCREL
再配置を確実に発行するようにすることができます。
ARM 上の Windows¶
スタックプローブの発行¶
リファレンス実装(Microsoft Visual Studio 2012)は、以下の方法でスタックプローブを発行します
movw r4, #constant
bl __chkstk
sub.w sp, sp, r4
ただし、これは32 MiB(±16MiB)の制限があります。より大きなバイナリに対応するために、LLVMは-mcmodel=large
を使用して、わずかな偏差を介して4GiBの範囲を許可することをサポートしています。以下のように間接ジャンプが生成されます
movw r4, #constant
movw r12, :lower16:__chkstk
movt r12, :upper16:__chkstk
blx r12
sub.w sp, sp, r4
可変長配列¶
リファレンス実装(Microsoft Visual Studio 2012)では、可変長配列(VLA)の発行は許可されていません。
Windows ARM Itanium ABI は、動的スタック割り当ての発行のサポートを追加することで、基本 ABI を拡張します。可変スタック割り当てを発行する場合、ガードページが正しく設定されていることを確認するために、__chkstk
の呼び出しが無条件に発行されます。このスタックプローブ発行の発行は、標準のスタックプローブ発行と同様に処理されます。
MSVC 環境は、現在 VLA のコードを発行しません。
ARM64 上の Windows¶
スタックプローブの発行¶
リファレンス実装(Microsoft Visual Studio 2017)は、以下の方法でスタックプローブを発行します
mov x15, #constant
bl __chkstk
sub sp, sp, x15, lsl #4
ただし、これは 256 MiB(±128MiB)の制限があります。より大きなバイナリに対応するために、LLVM は -mcmodel=large
を使用して、わずかな偏差を介して 8GiB(±4GiB)の範囲を許可することをサポートしています。以下のように間接ジャンプが生成されます
mov x15, #constant
adrp x16, __chkstk
add x16, x16, :lo12:__chkstk
blr x16
sub sp, sp, x15, lsl #4