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