質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

Q&A

解決済

4回答

3563閲覧

アセンブラでのスタック領域の確保のされ方について

k-taguchi

総合スコア9

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

0グッド

0クリップ

投稿2020/09/03 14:03

知りたいこと

x86-64で、スタックフレームの確保され方を知りたいです。

x86-64 gcc8.1で以下のコードをコンパイルします。
コンパイルオプションは-O0(最適化なし)をつけています。

c

1#include <stdio.h> 2#include <string.h> 3void vuln(char *pass){ 4 char buf[50]; 5 strcpy(buf, pass); 6} 7 8int main(int argc, char** argv){ 9 vuln(argv[1]); 10 return 0; 11}

ディスアセンブルした結果が以下になります。

vuln: push rbp mov rbp, rsp sub rsp, 80 mov QWORD PTR [rbp-72], rdi mov rdx, QWORD PTR [rbp-72] lea rax, [rbp-64] mov rsi, rdx mov rdi, rax call strcpy nop leave ret main: push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], edi mov QWORD PTR [rbp-16], rsi mov rax, QWORD PTR [rbp-16] add rax, 8 mov rax, QWORD PTR [rax] mov rdi, rax call vuln mov eax, 0 leave ret

この時、関数vulnではスタックフレームは80バイト分確保されていることがわかります。

vuln: push rbp mov rbp, rsp sub rsp, 80 ← ここ

元のCのコードでは、buf[50]と記載されている通り、バッファは50バイト分しか確保していません。

スタックフレームの確保のされ方のルールをご教授ください。
または、そのルールが記載されているドキュメントがございましたら、ご教授いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

呼び出し規約、でぐぐってみよう。
おはなしはそれから。

投稿2020/09/03 14:10

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k-taguchi

2020/09/03 14:21

ありがとうございます。 どうぐぐったらいいかもわからなかったので、指針を決めることができました。 まずは、教えていただいたワードでぐぐって勉強します!
guest

0

最新のx86_64アーキテクチャにやGCCに詳しい訳ではないですが、一般的にCのコンパイラが出力するコードをアセンブラに落とすと、この様なバウンダリー調節みたいなコードが良く出力されます。有名どころでは構造体のメンバーがキッチリ詰まらないで、4や8の倍数位置に配置されることがあります。

今回ご提示のコードでは何らかの理由で16の倍数の大きさにする必要があったのだと思います。最近のCPUではメモリアクセス効率だけでは無く、キャッシュラインの割り当て(ヒット効率)を気にする必要があるのかも知れません。

と思って一応ぐぐったらば、一発でこんな記述がでました。コレが理由知れません。

https://ja.wikipedia.org/wiki/X64

AMD64には、元々はCMPXCHG16B命令はなかった。この命令は16バイト(128ビット)のメモリ領域を複数のCPUコアで排他的に共有することに使用される。この命令はWindowsで16TB以上の仮想メモリを使うために必要である。

投稿2020/09/03 14:43

ahidaka

総合スコア391

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k-taguchi

2020/09/03 15:26

情報ありがとうございます! 一読させていただきます!
guest

0

bufのサイズを変えてどうなるか見てみました。

sh

1for i in {0..60..2} 2do 3 cat > aa.c <<-EOF 4 #include <stdio.h> 5 #include <string.h> 6 void vuln(char *pass){ 7 char buf[$i]; 8 strcpy(buf, pass); 9 } 10 11 int main(int argc, char** argv){ 12 vuln(argv[1]); 13 return 0; 14 } 15 EOF 16 gcc -O0 -S aa.c 17 echo $i `grep subq aa.s | head -1` 18done

plain

10 subq $16, %rsp 22 subq $32, %rsp 34 subq $32, %rsp 46 subq $32, %rsp 58 subq $32, %rsp 610 subq $32, %rsp 712 subq $32, %rsp 814 subq $32, %rsp 916 subq $32, %rsp 1018 subq $48, %rsp 1120 subq $48, %rsp 1222 subq $48, %rsp 1324 subq $48, %rsp 1426 subq $48, %rsp 1528 subq $48, %rsp 1630 subq $48, %rsp 1732 subq $48, %rsp 1834 subq $64, %rsp 1936 subq $64, %rsp 2038 subq $64, %rsp 2140 subq $64, %rsp 2242 subq $64, %rsp 2344 subq $64, %rsp 2446 subq $64, %rsp 2548 subq $64, %rsp 2650 subq $80, %rsp 2752 subq $80, %rsp 2854 subq $80, %rsp 2956 subq $80, %rsp 3058 subq $80, %rsp 3160 subq $80, %rsp

「ローカル変数サイズを16バイト単位に切り上げ+引き数サイズを16バイト単位に切り上げ」のようです。
コードは省略しますが、引き数なしにしてpassをグローバル変数渡しにすると、16バイト減ります(bufサイズ0を除く)ので、追加の16バイトは引き数分でしょう。

投稿2020/09/03 15:47

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k-taguchi

2020/09/04 12:07

ご回答ありがとうございます! 他の方の回答も含め、参考にさせていただきます!
guest

0

詳しく見てないですが多分こんな感じだと思います。

ローカル変数分50バイト以上→キリの良い64バイトに繰り上げ
リターンアドレス→8バイト
引数sizeof(char*)分→8バイト

合計80バイト

投稿2020/09/03 14:36

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

k-taguchi

2020/09/03 15:27

確かに計算は合いますね。 他の方からの情報も併せて確認させていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問