回答編集履歴
5
訂正を追加
answer
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
>
|
1
|
+
> sub esp, 136の136は値なのか、アドレスなのか
|
2
2
|
|
3
3
|
値です。
|
4
4
|
|
5
|
-
>
|
5
|
+
> sub esp, 136はespに136を入れてるイメージでいいのか
|
6
6
|
|
7
7
|
違います。代入ではありません。
|
8
8
|
sub は subtract 引き算という意味です。
|
9
9
|
sub esp, 136 は esp = esp - 136 という引き算です。
|
10
10
|
esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域の中のポイントするメモリが変わります。それはスタック領域のトップ位置が変化することになる…と言ってわかるかな?図示できると良いのだけど今は…。
|
11
11
|
|
12
|
-
>
|
12
|
+
> 以下の部分では何をしているのか、なぜ136と8を分けて足してるのか、レジスタの中で何が起きているのか
|
13
13
|
|
14
14
|
繰り返しますが、足し算ではなく、引き算です。
|
15
15
|
|
@@ -26,19 +26,24 @@
|
|
26
26
|
136バイトの領域と8バイトの領域は、使う目的が違う=出処が違うので、別の命令が生成されたのです。でも、2つの連続した sub esp 命令は、次の一命令に置き換えることができます。
|
27
27
|
sub esp, 144 // esp = esp - 144
|
28
28
|
|
29
|
-
人間がプログラムするなら、容易に一命令にまとめられますが、おそらくコンパイラの最適化レベルが低い(最適化オプションを指定していない?)
|
29
|
+
人間がプログラムするなら、容易に一命令にまとめられますが、おそらくコンパイラの最適化レベルが低い(最適化オプションを指定していない?)ので、まとめられなかったのでしょう。
|
30
30
|
|
31
|
-
>
|
31
|
+
> call <strcpy>は関数strcpyのアドレスをどこに保存しているのか?
|
32
32
|
|
33
33
|
これをアセンブルする時点で strcpy のアドレスは不明です。アセンブラは、アドレスはわからないけど、call命令の機械語命令とバイト数は当然わかってる…
|
34
|
-
具体的に言うと call strcpy は 0xE8 0x?? 0x?? 0x?? 0x?? という5バイトの機械語命令にアセンブルされると思われ、4バイトの 0x?? は strcpy のアドレスが書かれる所なのだけど、この時点で strcpy のアドレスは決まらないので、この4バイトを 0x?? のままにしている…アドレスに相当する部分の機械語コードを空欄にしてアセンブルしておくのです。
|
34
|
+
具体的に言うと call strcpy は 0xE8 0x?? 0x?? 0x?? 0x?? という5バイトの機械語命令にアセンブルされると思われ、4バイトの 0x?? は~~ strcpy のアドレス~~が書かれる所なのだけど、この時点で strcpy のアドレスは決まらないので、この4バイトを 0x?? のままにしている…アドレスに相当する部分の機械語コードを空欄にしてアセンブルしておくのです。
|
35
35
|
「保存」ではなく、後でアドレスを埋められるように「空欄」を作っておくということ。
|
36
36
|
|
37
37
|
コンパイル処理の中で、アセンブルの次(というか、最後)の処理はリンクです。
|
38
|
-
strcpy 関数の機械語コードはライブラリファイルの中にあります。それをこのプログラムと結合(linkage)します。結合した時点で strcpy のアドレスが確定するので、空欄を埋めることができる…先ほど空欄にしておいた 4バイトの 0x?? に確定したアドレスを書き込むことができて、実行可能なファイルができあがる、というわけです。
|
38
|
+
strcpy 関数の機械語コードはライブラリファイルの中にあります。それをこのプログラムと結合(linkage)します。結合した時点で strcpy のアドレスが確定するので、空欄を埋めることができる…先ほど空欄にしておいた 4バイトの 0x?? に~~確定したアドレス~~を書き込むことができて、実行可能なファイルができあがる、というわけです。
|
39
39
|
|
40
|
+
※上記、打ち消し線を引いた2ヵ所を「strcpy への距離」と訂正します。この距離は **call 命令の、次の命令の先頭アドレスが基準**です。それは今回 add 命令ですから
|
40
|
-
|
41
|
+
- 距離 = (strcpy のアドレス)-(add 命令の先頭アドレス)
|
41
42
|
|
43
|
+
と計算します。この値が4バイトの 0x?? に書かれます。以上、昨夜はアドレスか距離か、どちらか確信ないまま回答しましたが、いずれにしても、 strcpy のアドレス(と add 命令のアドレス)はリンク時に確定し、全ての機械語が確定する、という意味では大勢に違いありません(と言い訳するw)。
|
44
|
+
|
45
|
+
> 最後らへんでなぜ"add esp, 16"をしているのか?
|
46
|
+
|
42
47
|
call命令の直前にpush命令が2つ、それと上記の sub esp, 8 命令があります。
|
43
48
|
```asm
|
44
49
|
sub esp, 8 // esp = esp - 8
|
@@ -52,4 +57,4 @@
|
|
52
57
|
ひとつのpush命令は esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
|
53
58
|
スタックの値を元に戻したということから、ここの sub esp, 8 から add esp, 16 までの6命令が strcpy(s, a); という関数呼出しをコンパイルした部分として、ひとまとまりのコードと見ることができます。
|
54
59
|
|
55
|
-
|
60
|
+
不明点はまだあるでしょうから、コメントもしくは新たな質問で聞いてください。
|
4
ケアレスミス発見
answer
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
lea eax, [ebp-136] // eax に s[] の先頭アドレスを代入し、
|
21
21
|
push eax // eax をスタックトップにpushして strcpy に渡す
|
22
22
|
```
|
23
|
-
- 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)
|
23
|
+
- 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)すること。加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
|
24
24
|
- sub esp, 8 で、さらに8バイトの領域をスタックに確保した、ということ(たぶん、関数呼出しをする際の「作法」のようなもの、後述)。
|
25
25
|
|
26
26
|
136バイトの領域と8バイトの領域は、使う目的が違う=出処が違うので、別の命令が生成されたのです。でも、2つの連続した sub esp 命令は、次の一命令に置き換えることができます。
|
3
call 命令の機械語など、情報を追加
answer
CHANGED
@@ -13,17 +13,16 @@
|
|
13
13
|
|
14
14
|
繰り返しますが、足し算ではなく、引き算です。
|
15
15
|
|
16
|
-
```
|
16
|
+
```asm
|
17
|
-
sub esp, 136 // esp = esp - 136
|
17
|
+
sub esp, 136 // esp = esp - 136, s[128] を割り当てた
|
18
18
|
sub esp, 8 // esp = esp - 8
|
19
19
|
push dword [ebp+8] // この関数の引数 a の値を strcpy に渡そうとしている
|
20
|
-
lea eax, [ebp-136] // eax に s[] の先頭アドレスを代入
|
20
|
+
lea eax, [ebp-136] // eax に s[] の先頭アドレスを代入し、
|
21
|
+
push eax // eax をスタックトップにpushして strcpy に渡す
|
21
22
|
```
|
23
|
+
- 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)し、加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
|
24
|
+
- sub esp, 8 で、さらに8バイトの領域をスタックに確保した、ということ(たぶん、関数呼出しをする際の「作法」のようなもの、後述)。
|
22
25
|
|
23
|
-
- 136 は 128 + 8 です。おおきな目的は s[128] の領域を確保し、さらに8バイトの領域(用途は今、不明)をスタック領域に確保すること。
|
24
|
-
- sub esp, 8 で、さらに8バイトの領域をスタックに確保した、ということ(
|
25
|
-
(たぶん、関数呼出しをする際の「作法」のようなもの)。
|
26
|
-
|
27
26
|
136バイトの領域と8バイトの領域は、使う目的が違う=出処が違うので、別の命令が生成されたのです。でも、2つの連続した sub esp 命令は、次の一命令に置き換えることができます。
|
28
27
|
sub esp, 144 // esp = esp - 144
|
29
28
|
|
@@ -31,15 +30,17 @@
|
|
31
30
|
|
32
31
|
>・call <strcpy>は関数strcpyのアドレスをどこに保存しているのか?
|
33
32
|
|
34
|
-
これをアセンブルする時点で strcpy のアドレスは不明です。アセンブラは、アドレスはわからないけど、call命令の機械語命令とバイト数は当然わかってる
|
33
|
+
これをアセンブルする時点で strcpy のアドレスは不明です。アセンブラは、アドレスはわからないけど、call命令の機械語命令とバイト数は当然わかってる…
|
34
|
+
具体的に言うと call strcpy は 0xE8 0x?? 0x?? 0x?? 0x?? という5バイトの機械語命令にアセンブルされると思われ、4バイトの 0x?? は strcpy のアドレスが書かれる所なのだけど、この時点で strcpy のアドレスは決まらないので、この4バイトを 0x?? のままにしている…アドレスに相当する部分の機械語コードを空欄にしてアセンブルしておくのです。
|
35
|
+
「保存」ではなく、後でアドレスを埋められるように「空欄」を作っておくということ。
|
35
36
|
|
36
|
-
アセンブルの次の処理はリンクです。
|
37
|
+
コンパイル処理の中で、アセンブルの次(というか、最後)の処理はリンクです。
|
37
|
-
strcpy 関数の機械語コードはライブラリファイルの中にあります。それをこのプログラムと結合(linkage)します。結合した時点で strcpy のアドレスが確定
|
38
|
+
strcpy 関数の機械語コードはライブラリファイルの中にあります。それをこのプログラムと結合(linkage)します。結合した時点で strcpy のアドレスが確定するので、空欄を埋めることができる…先ほど空欄にしておいた 4バイトの 0x?? に確定したアドレスを書き込むことができて、実行可能なファイルができあがる、というわけです。
|
38
39
|
|
39
40
|
>・最後らへんでなぜ"add esp, 16"をしているのか?
|
40
41
|
|
41
42
|
call命令の直前にpush命令が2つ、それと上記の sub esp, 8 命令があります。
|
42
|
-
```
|
43
|
+
```asm
|
43
44
|
sub esp, 8 // esp = esp - 8
|
44
45
|
push dword [ebp+8] // esp = esp - 4
|
45
46
|
lea eax, [ebp-136]
|
@@ -49,5 +50,6 @@
|
|
49
50
|
```
|
50
51
|
二つのpush命令は strcpy(s, a) の実引数 s と a をスタックに書いて strcpy() に渡しています。
|
51
52
|
ひとつのpush命令は esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
|
53
|
+
スタックの値を元に戻したということから、ここの sub esp, 8 から add esp, 16 までの6命令が strcpy(s, a); という関数呼出しをコンパイルした部分として、ひとまとまりのコードと見ることができます。
|
52
54
|
|
53
55
|
とりいそぎ。まだ不明点があるでしょうから、コメントで聞いてください。
|
2
ケアレスミス発見
answer
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
違います。代入ではありません。
|
8
8
|
sub は subtract 引き算という意味です。
|
9
9
|
sub esp, 136 は esp = esp - 136 という引き算です。
|
10
|
-
esp はスタックポインタです。esp
|
10
|
+
esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域の中のポイントするメモリが変わります。それはスタック領域のトップ位置が変化することになる…と言ってわかるかな?図示できると良いのだけど今は…。
|
11
11
|
|
12
12
|
>・以下の部分では何をしているのか、なぜ136と8を分けて足してるのか、レジスタの中で何が起きているのか
|
13
13
|
|
1
ケアレスミス発見
answer
CHANGED
@@ -48,6 +48,6 @@
|
|
48
48
|
add esp, 16 // esp = esp + 16
|
49
49
|
```
|
50
50
|
二つのpush命令は strcpy(s, a) の実引数 s と a をスタックに書いて strcpy() に渡しています。
|
51
|
-
ひとつのpush命令は
|
51
|
+
ひとつのpush命令は esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
|
52
52
|
|
53
53
|
とりいそぎ。まだ不明点があるでしょうから、コメントで聞いてください。
|