質問編集履歴

5

コンパイル時のオプションを追記

2019/04/24 09:36

投稿

REIK727
REIK727

スコア23

test CHANGED
File without changes
test CHANGED
@@ -122,7 +122,7 @@
122
122
 
123
123
  (あっているかは置いといて)結論が出たので勉強の意味も込めて書いておきます。
124
124
 
125
- Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認したところ、このようになっていました。
125
+ Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認(gcc -S -O0 -fno-asynchronous-unwind-tables <ソース名>)したところ、このようになっていました。
126
126
 
127
127
  ```Assembly
128
128
 

4

軽微な修正

2019/04/24 09:36

投稿

REIK727
REIK727

スコア23

test CHANGED
File without changes
test CHANGED
@@ -216,7 +216,7 @@
216
216
 
217
217
  ```
218
218
 
219
- また、Chironian様のご指摘のようにgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
219
+ また、Chironian様のご指摘のようにやはりgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
220
220
 
221
221
  最終的に、スタックは恐らくこんな感じになっているのではないかと考えました。(なぜか1列のテーブルが作れなかったのでしかたなく2列にしています)
222
222
 
@@ -234,7 +234,7 @@
234
234
 
235
235
  |func関数のベースポインタ(8バイト)||
236
236
 
237
- |func関数を呼び出した地点への戻り番地(たぶん8バイト?)||
237
+ |main関数への戻り番地(たぶん8バイト?)||
238
238
 
239
239
  |パディング(16-12=4バイト)||
240
240
 

3

追記

2019/04/24 09:00

投稿

REIK727
REIK727

スコア23

test CHANGED
File without changes
test CHANGED
@@ -116,4 +116,136 @@
116
116
 
117
117
 
118
118
 
119
- 環境はWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
119
+ 環境はWindows10 home(64bit)のWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。
120
+
121
+ ### 追記
122
+
123
+ (あっているかは置いといて)結論が出たので勉強の意味も込めて書いておきます。
124
+
125
+ Zuishin様やcateye様がアドバイスしてくださったように一つ目のコードのアセンブルソースを確認したところ、このようになっていました。
126
+
127
+ ```Assembly
128
+
129
+ .file "1.c"
130
+
131
+ .text
132
+
133
+ .section .rodata
134
+
135
+ .LC0:
136
+
137
+ .string "%p,%p,%p\n"
138
+
139
+ .text
140
+
141
+ .globl func
142
+
143
+ .type func, @function
144
+
145
+ func:
146
+
147
+ pushq %rbp
148
+
149
+ movq %rsp, %rbp
150
+
151
+ subq $16, %rsp
152
+
153
+ leaq -12(%rbp), %rcx
154
+
155
+ leaq -8(%rbp), %rdx
156
+
157
+ leaq -4(%rbp), %rax
158
+
159
+ movq %rax, %rsi
160
+
161
+ movl $.LC0, %edi
162
+
163
+ movl $0, %eax
164
+
165
+ call printf
166
+
167
+ nop
168
+
169
+ leave
170
+
171
+ ret
172
+
173
+ .size func, .-func
174
+
175
+ .globl main
176
+
177
+ .type main, @function
178
+
179
+ main:
180
+
181
+ pushq %rbp
182
+
183
+ movq %rsp, %rbp
184
+
185
+ subq $16, %rsp
186
+
187
+ leaq -12(%rbp), %rcx
188
+
189
+ leaq -8(%rbp), %rdx
190
+
191
+ leaq -4(%rbp), %rax
192
+
193
+ movq %rax, %rsi
194
+
195
+ movl $.LC0, %edi
196
+
197
+ movl $0, %eax
198
+
199
+ call printf
200
+
201
+ movl $0, %eax
202
+
203
+ call func
204
+
205
+ movl $0, %eax
206
+
207
+ leave
208
+
209
+ ret
210
+
211
+ .size main, .-main
212
+
213
+ .ident "GCC: (GNU) 8.3.0"
214
+
215
+ .section .note.GNU-stack,"",@progbits
216
+
217
+ ```
218
+
219
+ また、Chironian様のご指摘のようにgccはスタックフレームの開始アドレスを16バイト単位に調整しているようです。上のアセンブリソースに`subq $16, %rsp`という命令があることからもそれが窺えますし、main関数内で宣言する変数をもっと増やしてみたら`subq $32, %rsp`と変化したことから間違いないかと思います。
220
+
221
+ 最終的に、スタックは恐らくこんな感じになっているのではないかと考えました。(なぜか1列のテーブルが作れなかったのでしかたなく2列にしています)
222
+
223
+ |||
224
+
225
+ |:---:|---|
226
+
227
+ |パディング(16-12=4バイト)||
228
+
229
+ |変数f(4バイト)||
230
+
231
+ |変数e(4バイト)||
232
+
233
+ |変数d(4バイト)||
234
+
235
+ |func関数のベースポインタ(8バイト)||
236
+
237
+ |func関数を呼び出した地点への戻り番地(たぶん8バイト?)||
238
+
239
+ |パディング(16-12=4バイト)||
240
+
241
+ |変数c(4バイト)||
242
+
243
+ |変数b(4バイト)||
244
+
245
+ |変数a(4バイト)||
246
+
247
+ |main関数のベースポインタ(8バイト)||
248
+
249
+
250
+
251
+ これが変数cと変数dの間の20バイトのギャップの正体ではないかなあと思いました。

2

行末に不要な空白が入っていたのが気持ち悪かったので修正

2019/04/24 08:57

投稿

REIK727
REIK727

スコア23

test CHANGED
File without changes
test CHANGED
@@ -16,29 +16,29 @@
16
16
 
17
17
  ```C
18
18
 
19
- #include<stdio.h>
19
+ #include<stdio.h>
20
20
 
21
- int func()
21
+ int func()
22
22
 
23
- {
23
+ {
24
24
 
25
- int d,e,f;
25
+ int d,e,f;
26
26
 
27
27
  printf("%p,%p,%p\n",&d,&e,&f);
28
28
 
29
- }
29
+ }
30
30
 
31
- int main()
31
+ int main()
32
32
 
33
- {
33
+ {
34
34
 
35
- int a,b,c;
35
+ int a,b,c;
36
36
 
37
37
  printf("%p,%p,%p\n",&a,&b,&c);
38
38
 
39
- func();
39
+ func();
40
40
 
41
- }
41
+ }
42
42
 
43
43
  ```
44
44
 
@@ -54,33 +54,33 @@
54
54
 
55
55
  ```C
56
56
 
57
- #include<stdio.h>
57
+ #include<stdio.h>
58
58
 
59
- int *p1,*p2;
59
+ int *p1,*p2;
60
60
 
61
- void func()
61
+ void func()
62
62
 
63
- {
63
+ {
64
64
 
65
- int d,e,f;p2=&d;
65
+ int d,e,f;p2=&d;
66
66
 
67
- printf("%p,%p,%p\n",&d,&e,&f);
67
+ printf("%p,%p,%p\n",&d,&e,&f);
68
68
 
69
- }
69
+ }
70
70
 
71
- int main()
71
+ int main()
72
72
 
73
- {
73
+ {
74
74
 
75
- int a,b,c;p1=&c;
75
+ int a,b,c;p1=&c;
76
76
 
77
- printf("%p,%p,%p\n",&a,&b,&c);
77
+ printf("%p,%p,%p\n",&a,&b,&c);
78
78
 
79
- func();
79
+ func();
80
80
 
81
81
  printf("%d\n",sizeof(int)*(p1-p2));
82
82
 
83
- }
83
+ }
84
84
 
85
85
  ```
86
86
 

1

2019/04/24 05:14

投稿

REIK727
REIK727

スコア23

test CHANGED
File without changes
test CHANGED
@@ -113,3 +113,7 @@
113
113
 
114
114
 
115
115
  int型は(私の環境だと)4バイトの大きさを持つので、スタック上で変数cの領域が終わってから変数dの領域が始まるまでに20バイトの空白?があるようです。これはどういった意味を持つのでしょうか?
116
+
117
+
118
+
119
+ 環境はWSL(ubuntu)、コンパイラはgcc8.3.0でオプションは特につけてないです。