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

質問編集履歴

5

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

2019/04/24 09:36

投稿

REIK727
REIK727

スコア23

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

軽微な修正

2019/04/24 09:36

投稿

REIK727
REIK727

スコア23

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
- |func関数を呼び出した地点への戻り番地(たぶん8バイト?)||
119
+ |main関数への戻り番地(たぶん8バイト?)||
120
120
  |パディング(16-12=4バイト)||
121
121
  |変数c(4バイト)||
122
122
  |変数b(4バイト)||

3

追記

2019/04/24 09:00

投稿

REIK727
REIK727

スコア23

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

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

2019/04/24 08:57

投稿

REIK727
REIK727

スコア23

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

2019/04/24 05:14

投稿

REIK727
REIK727

スコア23

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でオプションは特につけてないです。