teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

5

訂正を追加

2019/08/02 11:03

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -1,15 +1,15 @@
1
- >sub esp, 136の136は値なのか、アドレスなのか
1
+ > sub esp, 136の136は値なのか、アドレスなのか
2
2
 
3
3
  値です。
4
4
 
5
- >sub esp, 136はespに136を入れてるイメージでいいのか
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
- >以下の部分では何をしているのか、なぜ136と8を分けて足してるのか、レジスタの中で何が起きているのか
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
- >call <strcpy>は関数strcpyのアドレスをどこに保存しているのか?
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
- >・最後らへんでなぜ"add esp, 16"をしているか?
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

ケアレスミス発見

2019/08/02 11:03

投稿

rubato6809
rubato6809

スコア1382

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] となるメモリ領域を確保(割当て)し、加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
23
+ - 136 は 128 + 8 です。主な目的は s[128] となるメモリ領域を確保(割当て)すること。加えて8バイトの領域(用途は今、不明)もスタック領域に確保すること。
24
24
  - sub esp, 8 で、さらに8バイトの領域をスタックに確保した、ということ(たぶん、関数呼出しをする際の「作法」のようなもの、後述)。
25
25
 
26
26
  136バイトの領域と8バイトの領域は、使う目的が違う=出処が違うので、別の命令が生成されたのです。でも、2つの連続した sub esp 命令は、次の一命令に置き換えることができます。

3

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

2019/08/01 15:44

投稿

rubato6809
rubato6809

スコア1382

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

ケアレスミス発見

2019/08/01 15:19

投稿

rubato6809
rubato6809

スコア1382

answer CHANGED
@@ -7,7 +7,7 @@
7
7
  違います。代入ではありません。
8
8
  sub は subtract 引き算という意味です。
9
9
  sub esp, 136 は esp = esp - 136 という引き算です。
10
- esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域のトップ位置が変化しまと言ってわかるかな?図示できると良いのだけど今は…
10
+ esp はスタックポインタです。esp はメモリのアドレスを値として持っています。esp に対して引き算や足し算をすると、スタック領域の中のポインするメモリが変わります。それはスタク領域のトップ位置が変化するこになる…と言ってわかるかな?図示できると良いのだけど今は…。
11
11
 
12
12
  >・以下の部分では何をしているのか、なぜ136と8を分けて足してるのか、レジスタの中で何が起きているのか
13
13
 

1

ケアレスミス発見

2019/08/01 13:46

投稿

rubato6809
rubato6809

スコア1382

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命令は、strcpy( esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
51
+ ひとつのpush命令は esp の値を 4 減らします(esp = esp - 4)。上にコメントしたように、8, 4, 4 が esp から引かれているので、これらの分をまとめて元に戻すのが add esp, 16 です。
52
52
 
53
53
  とりいそぎ。まだ不明点があるでしょうから、コメントで聞いてください。