回答編集履歴

5

訂正を追加

2019/08/02 11:03

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -1,4 +1,4 @@
1
- >sub esp, 136の136は値なのか、アドレスなのか
1
+ > sub esp, 136の136は値なのか、アドレスなのか
2
2
 
3
3
 
4
4
 
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
 
9
- >sub esp, 136はespに136を入れてるイメージでいいのか
9
+ > sub esp, 136はespに136を入れてるイメージでいいのか
10
10
 
11
11
 
12
12
 
@@ -20,7 +20,7 @@
20
20
 
21
21
 
22
22
 
23
- >以下の部分では何をしているのか、なぜ136と8を分けて足してるのか、レジスタの中で何が起きているのか
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
- >call <strcpy>は関数strcpyのアドレスをどこに保存しているのか?
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
- >最後らへんでなぜ"add esp, 16"をしているのか?
89
+ > 最後らへんでなぜ"add esp, 16"をしているのか?
80
90
 
81
91
 
82
92
 
@@ -106,4 +116,4 @@
106
116
 
107
117
 
108
118
 
109
- とりいそぎ。まだ不明点あるでしょうから、コメントで聞いてください。
119
+ 不明点はまだあるでしょうから、コメントもしくは新たな質問で聞いてください。

4

ケアレスミス発見

2019/08/02 11:03

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -42,7 +42,7 @@
42
42
 
43
43
  ```
44
44
 
45
- - 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)し、加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
45
+ - 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)すること。加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
46
46
 
47
47
  - sub esp, 8 で、さらに8バイトの領域をスタックに確保した、ということ(たぶん、関数呼出しをする際の「作法」のようなもの、後述)。
48
48
 

3

call 命令の機械語など、情報を追加

2019/08/01 15:44

投稿

rubato6809
rubato6809

スコア1380

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

ケアレスミス発見

2019/08/01 15:19

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  sub esp, 136 は esp = esp - 136 という引き算です。
18
18
 
19
- esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域のトップ位置が変化しまと言ってわかるかな?図示できると良いのだけど今は…
19
+ esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域の中のポインするメモリが変わります。それはスタク領域のトップ位置が変化するこになる…と言ってわかるかな?図示できると良いのだけど今は…。
20
20
 
21
21
 
22
22
 

1

ケアレスミス発見

2019/08/01 13:46

投稿

rubato6809
rubato6809

スコア1380

test CHANGED
@@ -98,7 +98,7 @@
98
98
 
99
99
  二つのpush命令は strcpy(s, a) の実引数 s と a をスタックに書いて strcpy() に渡しています。
100
100
 
101
- ひとつのpush命令は、strcpy( esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
101
+ ひとつのpush命令は esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
102
102
 
103
103
 
104
104