[解決済み] GNUアセンブラを使ってx86_64でprintfを呼び出す
質問
GNUアセンブラで使用するために、AT&T構文でプログラムを書きました。
.data
format: .ascii "%d\n"
.text
.global main
main:
mov $format, %rbx
mov (%rbx), %rdi
mov $1, %rsi
call printf
ret
私は GCC でアセンブルとリンクを行います。
gcc -o main main.s
このコマンドで実行しています。
./main
プログラムを実行するとセグメンテーションフォールトが発生します。gdbを使うと、次のように表示されます。
printf
が見つかりません。.extern printf"を試しましたが、うまくいきません。ある人が、以下を呼び出す前にスタックポインタを保存するべきだと言いました。
printf
の前にリストアし
RET
どうすればいいのでしょうか?
どのように解決するのですか?
このコードには、いくつかの問題があります。その AMD64 システム V ABI Linuxで使用されている呼び出し規約は、いくつかのことを要求しています。それは CALL スタックが少なくとも16バイト(または32バイト)アラインであること。
入力引数領域の終端は、16(_m256の場合は32)にアライメントされていなければならない。 バイトのバウンダリで渡される。
の後に
C
ランタイムは
main
によってリターンポインタがスタック上に配置されたため、スタックの位置が8つずれています。
CALL
. 16 バイトの境界線に再調整するためには、単純に
PUSH
任意の
汎用レジスタをスタック上に配置し
POP
を最後に削除します。
また、呼び出し規約では AL には、可変長引数関数に使用されるベクターレジスタの数が含まれます。
al は、可変数の引数を必要とする関数に渡されるベクトル引数の数を示すために使用されます。
printf
は可変引数関数なので
AL
を設定する必要があります。この場合、ベクターレジスターでパラメータを渡さないので
AL
を0に設定します。
また、$formatポインタがすでにアドレスであるにもかかわらず、そのポインタを再参照しています。だからこれは間違っている。
mov $format, %rbx
mov (%rbx), %rdi
これは、formatのアドレスを取り、それを RBX . そして、そのアドレスの8バイトを RBX に配置し RDI . RDI である必要があります。 ポインタ を、文字そのものではなく、文字列に変換します。この2行は、次のように置き換えることができる。
lea format(%rip), %rdi
これはRIP Relative Addressingを使用しています。
また
NUL
は文字列を終了させます。を使うよりも、むしろ
.ascii
を使用することができます。
.asciz
をx86プラットフォームで使用することができます。
あなたのプログラムの動作バージョンは次のようになります。
# global data #
.data
format: .asciz "%d\n"
.text
.global main
main:
push %rbx
lea format(%rip), %rdi
mov $1, %esi # Writing to ESI zero extends to RSI.
xor %eax, %eax # Zeroing EAX is efficient way to clear AL.
call printf
pop %rbx
ret
その他の推奨事項/提案
また、64ビット版LinuxのABIでは、呼び出しの規約で、特定のレジスタの保存を尊重するよう記述された関数があることも知っておく必要があります。レジスタの一覧と、それらが保存されるべきかどうかは、以下の通りです。
というレジスタは
Yes
の中に
をまたいで保存される
関数呼び出し
の列は、関数全体で保存されていることを確認する必要があります。関数
main
は、他の
C
関数を使用します。
読み取り専用であることが分かっている文字列やデータについては
.rodata
セクションで
.section .rodata
よりも
.data
64ビットモードの場合:32ビットレジスタである目的オペランドがある場合、CPUは64ビットレジスタ全体にわたってレジスタをゼロ拡張します。これにより、命令エンコーディングのバイト数を節約することができます。
実行ファイルが位置独立コードとしてコンパイルされている可能性があります。以下のようなエラーが表示されることがあります。
<ブロッククオート再配置 R_X86_64_PC32 シンボル `printf@@GLIBC_2.2.5' に対して、共有オブジェクトを作成するときに使用することができません; -fPIC で再コンパイルしてください。
これを解決するには、外部関数
printf
このように
call printf@plt
を経由して外部ライブラリ関数を呼び出します。 プロシージャ・リンケージ・テーブル(PLT)
関連
-
[解決済み】nohupプロセスをkillするためにプロセスIDを取得する方法?
-
[解決済み] gzip: stdin: not in gzip format tar: 子プロセスがステータス 1 を返しました。エラーは回復不可能:現在終了中
-
[解決済み】Linuxのdocker-composeでパーミッションが拒否されました【終了】。
-
[解決済み】git clone時に「'https'のリモートヘルパーが見つかりません。
-
[解決済み] エラー: gdal がインストールされているのに、R 依存パッケージのインストール中に gdal-config が見つからない
-
[解決済み] MongoDBへの接続が拒否された errno 111
-
[解決済み] アセンブリの制約
-
[解決済み] php] <defunct>のプロセスを削除することはできますか?
-
[解決済み] gccでC/C++のソースからアセンブラ出力を得るにはどうしたらいいですか?
-
[解決済み] setup script exited with error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】PytorchがCUDAは利用できないと言う件
-
[解決済み] linuxでpsから特定のプロセスをgrepする方法は?
-
[解決済み] chmod: 'my_script.sh' のパーミッションを変更しました。操作が許可されていない
-
[解決済み] "grep -q" のポイントは?
-
[解決済み] Gccコンパイル "オブジェクトファイルのサフィックスを計算できない: コンパイルできない"
-
[解決済み] 共有メモリページとフォーク
-
[解決済み] vimdiff の出力ファイルにおける +-- の意味は何ですか?それをオフにする方法は?
-
[解決済み] Tarエラーです。アーカイブ内の予期しないEOF
-
[解決済み] アセンブリの制約
-
[解決済み] bashの「#$」はどういう意味ですか?