質問編集履歴
5
コンパイル時のオプションを追記
title
CHANGED
File without changes
|
body
CHANGED
@@ -60,7 +60,7 @@
|
|
60
60
|
環境はWindows10 home(64bit)のWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
|
61
61
|
### 追記
|
62
62
|
(あっているかは置いといて)結論が出たので勉強の意味も込めて書いておきます。
|
63
|
-
Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認したところ、このようになっていました。
|
63
|
+
Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認(gcc -S -O0 -fno-asynchronous-unwind-tables <ソース名>)したところ、このようになっていました。
|
64
64
|
```Assembly
|
65
65
|
.file "1.c"
|
66
66
|
.text
|
4
軽微な修正
title
CHANGED
File without changes
|
body
CHANGED
@@ -107,7 +107,7 @@
|
|
107
107
|
.ident "GCC: (GNU) 8.3.0"
|
108
108
|
.section .note.GNU-stack,"",@progbits
|
109
109
|
```
|
110
|
-
また、Chironian様のご指摘のようにgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
|
110
|
+
また、Chironian様のご指摘のようにやはりgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
|
111
111
|
最終的に、スタックは恐らくこんな感じになっているのではないかと考えました。(なぜか1列のテーブルが作れなかったのでしかたなく2列にしています)
|
112
112
|
|||
|
113
113
|
|:---:|---|
|
@@ -116,7 +116,7 @@
|
|
116
116
|
|変数e(4バイト)||
|
117
117
|
|変数d(4バイト)||
|
118
118
|
|func関数のベースポインタ(8バイト)||
|
119
|
-
|
|
119
|
+
|main関数への戻り番地(たぶん8バイト?)||
|
120
120
|
|パディング(16-12=4バイト)||
|
121
121
|
|変数c(4バイト)||
|
122
122
|
|変数b(4バイト)||
|
3
追記
title
CHANGED
File without changes
|
body
CHANGED
@@ -57,4 +57,70 @@
|
|
57
57
|
|
58
58
|
int型は(私の環境だと)4バイトの大きさを持つので、スタック上で変数cの領域が終わってから変数dの領域が始まるまでに20バイトの空白?があるようです。これはどういった意味を持つのでしょうか?
|
59
59
|
|
60
|
-
環境はWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
|
60
|
+
環境はWindows10 home(64bit)のWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
|
61
|
+
### 追記
|
62
|
+
(あっているかは置いといて)結論が出たので勉強の意味も込めて書いておきます。
|
63
|
+
Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認したところ、このようになっていました。
|
64
|
+
```Assembly
|
65
|
+
.file "1.c"
|
66
|
+
.text
|
67
|
+
.section .rodata
|
68
|
+
.LC0:
|
69
|
+
.string "%p,%p,%p\n"
|
70
|
+
.text
|
71
|
+
.globl func
|
72
|
+
.type func, @function
|
73
|
+
func:
|
74
|
+
pushq %rbp
|
75
|
+
movq %rsp, %rbp
|
76
|
+
subq $16, %rsp
|
77
|
+
leaq -12(%rbp), %rcx
|
78
|
+
leaq -8(%rbp), %rdx
|
79
|
+
leaq -4(%rbp), %rax
|
80
|
+
movq %rax, %rsi
|
81
|
+
movl $.LC0, %edi
|
82
|
+
movl $0, %eax
|
83
|
+
call printf
|
84
|
+
nop
|
85
|
+
leave
|
86
|
+
ret
|
87
|
+
.size func, .-func
|
88
|
+
.globl main
|
89
|
+
.type main, @function
|
90
|
+
main:
|
91
|
+
pushq %rbp
|
92
|
+
movq %rsp, %rbp
|
93
|
+
subq $16, %rsp
|
94
|
+
leaq -12(%rbp), %rcx
|
95
|
+
leaq -8(%rbp), %rdx
|
96
|
+
leaq -4(%rbp), %rax
|
97
|
+
movq %rax, %rsi
|
98
|
+
movl $.LC0, %edi
|
99
|
+
movl $0, %eax
|
100
|
+
call printf
|
101
|
+
movl $0, %eax
|
102
|
+
call func
|
103
|
+
movl $0, %eax
|
104
|
+
leave
|
105
|
+
ret
|
106
|
+
.size main, .-main
|
107
|
+
.ident "GCC: (GNU) 8.3.0"
|
108
|
+
.section .note.GNU-stack,"",@progbits
|
109
|
+
```
|
110
|
+
また、Chironian様のご指摘のようにgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
|
111
|
+
最終的に、スタックは恐らくこんな感じになっているのではないかと考えました。(なぜか1列のテーブルが作れなかったのでしかたなく2列にしています)
|
112
|
+
|||
|
113
|
+
|:---:|---|
|
114
|
+
|パディング(16-12=4バイト)||
|
115
|
+
|変数f(4バイト)||
|
116
|
+
|変数e(4バイト)||
|
117
|
+
|変数d(4バイト)||
|
118
|
+
|func関数のベースポインタ(8バイト)||
|
119
|
+
|func関数を呼び出した地点への戻り番地(たぶん8バイト?)||
|
120
|
+
|パディング(16-12=4バイト)||
|
121
|
+
|変数c(4バイト)||
|
122
|
+
|変数b(4バイト)||
|
123
|
+
|変数a(4バイト)||
|
124
|
+
|main関数のベースポインタ(8バイト)||
|
125
|
+
|
126
|
+
これが変数cと変数dの間の20バイトのギャップの正体ではないかなあと思いました。
|
2
行末に不要な空白が入っていたのが気持ち悪かったので修正
title
CHANGED
File without changes
|
body
CHANGED
@@ -7,18 +7,18 @@
|
|
7
7
|
|
8
8
|
この認識が正しいかどうかを確かめるため、以下のようなコードを書いてみました。
|
9
9
|
```C
|
10
|
-
#include<stdio.h>
|
10
|
+
#include<stdio.h>
|
11
|
-
int func()
|
11
|
+
int func()
|
12
|
-
{
|
12
|
+
{
|
13
|
-
int d,e,f;
|
13
|
+
int d,e,f;
|
14
14
|
printf("%p,%p,%p\n",&d,&e,&f);
|
15
|
-
}
|
15
|
+
}
|
16
|
-
int main()
|
16
|
+
int main()
|
17
|
-
{
|
17
|
+
{
|
18
|
-
int a,b,c;
|
18
|
+
int a,b,c;
|
19
19
|
printf("%p,%p,%p\n",&a,&b,&c);
|
20
|
-
func();
|
20
|
+
func();
|
21
|
-
}
|
21
|
+
}
|
22
22
|
```
|
23
23
|
この実行結果が以下の通りです。
|
24
24
|
> 0x7ffff9c51f2c,0x7ffff9c51f28,0x7ffff9c51f24
|
@@ -26,20 +26,20 @@
|
|
26
26
|
|
27
27
|
予想通り変数a,b,cは連続した領域に並んでおり、またd,e,fも連続しています。しかしcとdの間に謎のギャップが存在します。そこで以下のようなコードを書いてみました。
|
28
28
|
```C
|
29
|
-
#include<stdio.h>
|
29
|
+
#include<stdio.h>
|
30
|
-
int *p1,*p2;
|
30
|
+
int *p1,*p2;
|
31
|
-
void func()
|
31
|
+
void func()
|
32
|
-
{
|
32
|
+
{
|
33
|
-
int d,e,f;p2=&d;
|
33
|
+
int d,e,f;p2=&d;
|
34
|
-
printf("%p,%p,%p\n",&d,&e,&f);
|
34
|
+
printf("%p,%p,%p\n",&d,&e,&f);
|
35
|
-
}
|
35
|
+
}
|
36
|
-
int main()
|
36
|
+
int main()
|
37
|
-
{
|
37
|
+
{
|
38
|
-
int a,b,c;p1=&c;
|
38
|
+
int a,b,c;p1=&c;
|
39
|
-
printf("%p,%p,%p\n",&a,&b,&c);
|
39
|
+
printf("%p,%p,%p\n",&a,&b,&c);
|
40
|
-
func();
|
40
|
+
func();
|
41
41
|
printf("%d\n",sizeof(int)*(p1-p2));
|
42
|
-
}
|
42
|
+
}
|
43
43
|
```
|
44
44
|
このプログラムを何回か実行した結果が以下の通りです。
|
45
45
|
> 0x7fffd5b3aa4c,0x7fffd5b3aa48,0x7fffd5b3aa44
|
1
title
CHANGED
File without changes
|
body
CHANGED
@@ -55,4 +55,6 @@
|
|
55
55
|
24
|
56
56
|
...
|
57
57
|
|
58
|
-
int型は(私の環境だと)4バイトの大きさを持つので、スタック上で変数cの領域が終わってから変数dの領域が始まるまでに20バイトの空白?があるようです。これはどういった意味を持つのでしょうか?
|
58
|
+
int型は(私の環境だと)4バイトの大きさを持つので、スタック上で変数cの領域が終わってから変数dの領域が始まるまでに20バイトの空白?があるようです。これはどういった意味を持つのでしょうか?
|
59
|
+
|
60
|
+
環境はWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
|