質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

5回答

9399閲覧

C言語でスタック領域内を覗く

strike1217

総合スコア651

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/05/13 14:25

編集2017/05/13 15:45

C

1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 int main(int argc, char* argv[]){ 6 int i; 7 char x[5]; 8 char text[1024]; 9 strcpy(text, argv[1]); 10 11 for(i = 0; i < 5; i++) 12 x[i] = i; 13 printf("%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p\n\n"); 14 15 printf(text); 16 printf("\n%p, %p, %p, %p, %p, %p\n", &i, &x[0], &x[1], &x[2], &x[3], &x[4]); 17 return 0; 18 }

結果が大量なの省略しますが、

> cat stack_overflow.txt | grep 0x7ffecd83e0 ,,,0x7fabd759d127, 0x7ffecd83e060, 0x7ffecd83dec8,,,0x7ffecd83e030, 0x7ffecd83e090,,,0x7ffecd83e058,,,0x7ffecd83e090,,,0x7ffecd83e030,,,, 0x7ffecd83e06c, 0x7ffecd83e067, 0x7ffecd83e068, 0x7ffecd83e069, 0x7ffecd83e06a, 0x7ffecd83e06b

となるのですが、
隣り合わせの、0x7fabd759d127, 0x7ffecd83e060, 0x7ffecd83dec8を計算すると

Bash

1echo "ibase = 16;7FFECD83E060 - 7FFECD83DEC8" | bc 2408 3 4echo "ibase = 16;7FABD759D127 - 7FFECD83E060" | bc 5-356317269817 6

となりました。

char x[5]の全要素は0x7ffecd83e060,の辺りあるはずです。たぶん・・・

アドレスの順番が結構デタラメで順序よく入っているわけではないようですが、char x[5] の全要素の連続するアドレスがどこにあるかを調べようとしても出てこなかったのです。
%pの数が大きくなりすぎて・・・

%pによるスタック領域のアドレスの確認の結果、アドレスの差が結構大きくなっている理由は何ですか?
スタック領域を見ているはずなのに、どうして、char x[5]のアドレスが出現しないのでしょうか?
%pを連続的にならべてprintf()を行っているのですが、なんかスタック領域のアドレスを見ているというより、何のアドレス群なのか分からなくなってきてしまったのですが・・・

どなたか教えてください。
Linux 64bit です。

「追記」

C

1#include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 5 int main(int argc, char* argv[]){ 6 int i; 7 int x[20]; 8 char text[1024]; 9 strcpy(text, argv[1]); 10 11 for(i = 0; i < 20; i++) 12 x[i] = i; 13 14 printf(text); 15 printf("\n%p, %p, %p, %p, %p, %p\n", &i, &x[0], &x[1], &x[2], &x[3], &x[4]); 16 return 0; 17 } 18
./stack_overflow %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x > stack_overflow.txt cat stack_overflow.txt b055bae0,13,252c7825,18f5c840,b4ebda50,b055b138,b055ac78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,252c7825,2c78252c,78252c78,b50cfd58,1,0,1,b50d29d8,0,5e400000,0,b50d34c0,b055ad50,18f5c391,b50d29d8,b055ad40,b4eae740,3de00ec7,ffffffff,b4b2f7f0,b4b16b98,b50cf4c0,b4b10000,398020,b055af20,b4c2f6e5,0,0,0,b056d1d8,0,0,0,b4eaea20,b50d29d8,b4eb7124,7,8,b50d3700,b056d1a8,b056d298 0x7ffcb055b04c, 0x7ffcb055aff0, 0x7ffcb055aff4, 0x7ffcb055aff8, 0x7ffcb055affc, 0x7ffcb055b000

となったときに、
おそらく、b055bae0,13,252c7825,18f5c840,b4ebda50,b055b138,b055ac78
の部分に int i ~ int x[5] の値が含まれているはずです。
それがどれなのかをみつけたいのです。

ちなみに、大部分は以下のようなコードがが占めています。
printf "\x25\x78\x2c\n"
%x,

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

参考までに。

C言語の文法の中では「スタックを使う」という決まりごとは存在しません。「コンパイラの性質上、ローカル変数はスタックに置かれる傾向が強い」といえる程度です。また、変数のアドレスの選び方も(配列や構造体の中の並びを除いて)特に決まりごとがあるわけではありません。

投稿2017/05/13 17:22

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

皆さんのおっしゃっている通り、変数がどこに配置されるかは処理系依存です。
ただ、オートマチック変数は、その特性上、すなわち、関数の呼び出し順に割り当てられ、呼び出しと逆順に解放されるため、レジスタに割り当てられるものを除いて、スタックに割り当てられることが極めて多いです。

1回の関数呼び出しで作られるスタック上の領域をスタックフレーム(構造体のようなもの)と呼びます。スタックフレームには、引数、リターンアドレス(関数から戻った後に実行されるコードのアドレス)、呼び出し元の関数のスタックフレームのアドレス(フレームポインタ)、オートマチック変数が含まれます。

7FABD759D127は、リターンアドレスではないでしょうか。コードの領域とスタックの領域はかなり離れていますから。

ちなみに、大部分は以下のようなコードがが占めています。

printf "\x25\x78\x2c\n"
%x,

これは、「strcpy(text, argv[1]);」した後の、「char text[1024];」すなわち、引数1の内容ではないですか?

投稿2017/05/13 23:20

編集2017/05/13 23:22
naomi3

総合スコア1105

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/05/14 04:00

「char text[1024]; のなかに、AAA以降の文字列が入っていることになりますね。
strike1217

2017/05/14 04:02

「7FABD759D127は、リターンアドレスではないでしょうか。」 なるほどです!!
strike1217

2017/05/14 04:20

スタック領域は底の方に行けば行くほど、アドレスは数値はおおきくなるんですか?
naomi3

2017/05/14 04:55

処理系依存ですが、スタック領域は底の方に行くほどアドレスが高くなる処理系が多いです。ご自身の環境もそのようですね。
strike1217

2017/05/14 05:11

ありがとうございます
guest

0

こんにちは。

下記でx[]のアドレスが出てきます。
x[]のアドレスはマシン語コードでスタック相対として存在しておりスタック上にはありません。
スタック上にp[]を確保して、そこへx[]のアドレスを放り込んでおけばスタック上にあるので出てきます。

C++

1#include<stdio.h> 2 3int main() 4{ 5 int i; 6 char x[5]; 7 8 char const* p[5]; 9 for(i = 0; i < 5; i++) 10 p[i]=&x[i]; 11 12 printf("%p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p, %p\n\n"); 13 printf("\n%p, %p, %p, %p, %p, %p\n", &i, &x[0], &x[1], &x[2], &x[3], &x[4]); 14 return 0; 15}

投稿2017/05/13 16:48

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/05/13 16:57

x[] はスタックないではないですか? えええ? そうなんですか!
strike1217

2017/05/13 16:59

実行してみたら、確かに出てきました。 すごいです!!
strike1217

2017/05/13 17:03

ローカル変数は、自動記憶領域としてスタックにあるのではなかったでしたっけ? 基本的なところにミスがあったかもしれません。
strike1217

2017/05/13 17:11

あ!変数の”アドレス”がスタック領域内にないということで、変数がスタック内にないわけではないんですね! わかりました。
strike1217

2017/05/13 17:24

int i = 378196; printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n"); とすれば、378196とでてきますよね?? 出てこなかったのですが、、、こちらはどうしてでしょうか?
Chironian

2017/05/13 18:41 編集

int i=0x12345678;などとして、printf("%llx, ...");とすれば出ました。 しかし、%xでは出ませんでした。不思議です。そもそも不正な使い方ですから、何が起きても可笑しくはないです。gccはprintf()の書式指定子を解釈しているので、何か思わぬことをしている可能性もあると思います。
strike1217

2017/05/14 03:59

なるほど! 自分もやってみます。
strike1217

2017/05/14 04:04

char x[5] = {'A', 'A', 'A', 'A', '0'}; だと、%xで出現しますね。
Chironian

2017/05/14 04:27

なるほど。 ま、この辺は処理系依存しまくりですから、特定の処理系の特定のバージョン限定なテクニックになりますので、あまり追求しても仕方がないと思います。
guest

0

1つ目のprintfで出力されるのはでたらめな値です。

というのも、%p書式は、引数自体のアドレスを表示するのではなく、引数に来たものをアドレスの書式で表示するだけなのです。たまたまメモリに入っていた値を表示しているだけで、何かのアドレスを意味するものでは全くありません。

投稿2017/05/13 14:34

maisumakun

総合スコア145186

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/05/13 14:36

げ! 変数の中身をアドレスの書式で表示しているということですか?
maisumakun

2017/05/13 14:42

そうです(下のprintfでは、&iのようにアドレスを自分から渡していますよね?)。 あと、x64では可変長引数であっても、最初のいくつか(Windowsは4つ、Linuxは6つ)の引数はレジスタ経由で渡される、とのことです。
strike1217

2017/05/13 14:45

char x[5]の値は、0, 1, 2, 3, 4で初期化しました。 %pであっても16進数で、0, 1, 2, 3, 4と連続で出てくるんではないんでしょでしょうか??
strike1217

2017/05/13 14:52

引数が最初の6つがレジスタ経由ということは、int i, char x[5]; は、スタック領域ではなく、レジスタにあるということでしょうか?? それとも、printf();の最初のパラメータ6つがレジスタ経由ということでしょうか??
Chironian

2017/05/13 15:18

横から失礼します。maisumakunさんの指摘は「1つめ」のprintfです。 多量の%pに対して出力する変数を一切指定していないですよ。
strike1217

2017/05/13 15:21

あ、これはですね。 普通は、%pではなく、%xを使うんですが、スタック領域を覗くセキュリティの技が存在するんです。 AAAA,%x,%x,%x,%x,%x,%x,%x みたいにchar *argv[] にパラメータを渡すとその中のスタック領域内を見るというものです。
Chironian

2017/05/13 15:38

良く分からないですが、1つ目のprintf()で出ているのは出鱈目な値なので、差分をとっても意味がないという話では? もしかして、1つ目のprintf()のどこかにx[]のアドレスが出てくることを期待しているのでしょうか? そのためには、スタック上にx[]のどれかをポイントしているポインタ変数が必要と思いますが、そのような変数はないのでは? また、2つ目のprintf()でそのような値をスタックに積んでますが、1つ目のprintf()実行時はまだそれは行われていません。
strike1217

2017/05/13 15:40

ええ。 プログラムをもっと簡単にして再度やってみました。 アドレスの取得は不可でした。 x[]のアドレスがどの位置にあるかを探しております。 追記します。
guest

0

セキュリティの技ですって?ばかばかしい笑。
スタック領域を覗くのに、そんな怪しげな技など不要です。普通にアクセスできる変数・配列がスタック領域に割当てられるのなら、”普通にメモリアクセスできる”に決まってるじゃありませんか。
メモリの何番地に何がどう割り当てられているか、デバッガを使って調べてもよいわけですが、ここは正攻法でメモリダンプしたら、いかが?

その前に、まず各ローカル変数のアドレスを表示して、メモリ上に、どんな順序で並んでいるか、確認しましょう。例えば、こんなふうに。

C

1 printf("argv: %p\n", &argv); 2 printf("argc: %p\n", &argc); 3 printf(" i: %p\n", &i); 4 printf(" x: %p\n", x); 5 printf("text: %p\n", text); 6

手元の64bit Linux、gcc version 5.4.0 で試したら、アドレスの若い方から、上記の順で配置されていました。よって、argv 変数のアドレスから、おおよそ各変数および配列の合計サイズ分だけ、メモリをダンプし、「メモリのリアルな姿」を直接見るのです(「おおよそ」とは、この辺りに、リターンアドレスや一時変数などの格納場所が割当てられている可能性があるから)。
手元で実行したら、こうなりました。

$ cc tera76041.c $ ./a.out helloWorld [helloWorld] argv: 0x7ffc48db0190 argc: 0x7ffc48db019c i: 0x7ffc48db01ac x: 0x7ffc48db01b0 text: 0x7ffc48db01c0 'stack area from &argv' 0x7ffc48db0190: b8 06 db 48 fc 7f 00 00 58 77 0c a8 02 00 00 00 ...H....Xw...... 0x7ffc48db01a0: 50 74 0c a8 0f 7f 00 00 18 02 db 48 05 00 00 00 Pt.........H.... 0x7ffc48db01b0: 00 01 02 03 04 00 00 00 3b 80 f7 00 00 00 00 00 ........;....... 0x7ffc48db01c0: 68 65 6c 6c 6f 57 6f 72 6c 64 00 48 fc 7f 00 00 helloWorld.H.... 0x7ffc48db01d0: f8 ef d0 a7 0f 7f 00 00 80 1d d0 a7 0f 7f 00 00 ................ 0x7ffc48db01e0: 14 02 db 48 fc 7f 00 00 e0 02 db 48 fc 7f 00 00 ...H.......H.... (以下、省略)

配列 x[5] は 0x7ffc48db01b0 から、正しく見えています。
配列 text[1024] の先頭アドレス 0x7ffc48db01e0 から、コマンドラインで与えた文字列 "HelloWorld" がコピーされて、見えています(念の為、これらのアドレスは実行する都度変化するので、いつぞやのアドレスランダム化が働いているのでしょう)。

思うに、メモリダンプを見ることが今の貴方には大事なんじゃありませんか。なので、大盤振る舞い(笑)で、メモリダンプ関数 mdump() をくっつけたコードを示します。他のプログラムでも同様にメモリダンプして、ご自身で解析してみてください。Enjoy !

C

1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <ctype.h> /* for isprint() */ 5void mdump(void*, int, char*); 6 7int main(int argc, char* argv[]) 8{ 9 int i; 10 char x[5]; 11 char text[1024]; 12 strcpy(text, argv[1]); 13 14 for(i = 0; i < 5; i++) 15 x[i] = i; 16 17 printf("[%s]\n", text); 18 19 printf("argv: %p\n", &argv); 20 printf("argc: %p\n", &argc); 21 printf(" i: %p\n", &i); 22 printf(" x: %p\n", x); 23 printf("text: %p\n", text); 24 printf("\n"); 25 mdump(&argv, sizeof(char**) + sizeof(int) * 2 + 26 sizeof(x) + sizeof(text), "stack area from &argv"); 27 28 return 0; 29} 30 31/*============================================================================ 32Func Name : void mdump(void *vp, int size, char *msg) 33Function : Dump memory 34Param Input : void *vp = memory address 35 int size = size to be dumped, 16 bytes align 36 char *msg = message to identify memory block 37Param Output, Return, Input Inf, Output Inf : None 38Revision : 1.00 2016/05/14 Created by rubato6809 39============================================================================*/ 40#define LINESIZE 16 // 16バイトを一行に表示 41 42void mdump(void *vp, int size, char *msg) 43{ 44 unsigned char *mem = vp; // 常に無符号char領域としてアクセス 45 int ltop, lnext; /* line-top and line-next */ 46 47 // 識別メッセージを表示 48 if (msg != NULL) { // つまり、NULLなら表示しない 49 printf(" '%s'", msg); 50 } 51 printf("\n"); // でも最初に改行だけはする 52 53 for (ltop = 0; ltop < size; ltop = lnext) { // LINESIZE 毎に繰返す 54 int i; 55 56 lnext = ltop + LINESIZE; // 次の行の先頭位置 57 printf("%p: ", &mem[ltop]); // 今の行の先頭アドレス 58 59 for (i = ltop; i < lnext; i++) // メモリの値を16進数で表示 60 printf("%02x ", mem[i]); 61 62 for (i = ltop; i < lnext; i++) { // 文字表示、ascii dump 63 unsigned char c = mem[i]; // メモリの値 64 printf("%c", isprint(c) ? c : '.'); // 表示不能なら '.' を 65 } 66 printf("\n"); 67 } 68} 69

投稿2017/05/20 17:15

rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

strike1217

2017/05/21 03:07

むむ・・・ 面白いです! 早速作ってみます。
strike1217

2017/05/21 14:30

GDBでもスタック領域の中を覗いてみたのですが、 スタック領域の中身は刻々と変化していくので分かりにくいんですよね・・・ 怪しげな、%p,%p,%p...もどの時点でのスタック領域なのかわからないんですよ 0x7ffffffde000: スタック領域開始アドレスなので、 char *start = 0x7ffffffde000; 終了がどこなのか分かりませんが・・・ ここかた全スタック領域内を覗くことができますよね??
rubato6809

2017/05/22 12:45

0x7ffffffde000: スタック領域開始アドレス??? 根拠は何か存じませんが、他の変数のアドレスより高いので、スタックの底(stack bottom)っぽいですね。ですから、スタック領域はそこから先ではありません。スタック領域は、そこから手前の、アドレスの若い領域にあるはずです。 そもそも、スタックは番地の若い方に伸びるという事を、知ってますか? 「GDBで…スタック領域の中身は刻々と変化していく」・・・さあ、どういうことが起こってるのか、私にはわかりませんけど、mdump() は、その時点のメモリを静的に表示するので、その点でも解析に有利だって事になりますね。何をしてるか、そんな難しいコードじゃありませんから、わかりますよね?
strike1217

2017/05/22 12:54

mdumpは分かりますね。
strike1217

2017/05/22 13:57

スタックの底に行けば行くほどアドレスが小さくなりますよね? 伸びる方向はアドレスの値が大きい方に伸びるのではないのでしょうか?
strike1217

2017/05/22 13:58

rubato6809さんのプログラムだと、argv: 0x7ffc48db0190が底に近いという事ですよね?
rubato6809

2017/05/22 14:01

上のプログラムの mdump() 呼出しを mdump(&argv, 0x4000, "stack area ?"); としてみて下さい。手元の結果は、こんなふうになりました。 $ ./a.out HelloWorld [HelloWorld] argv: 0x7ffd061595c0 argc: 0x7ffd061595cc i: 0x7ffd061595dc x: 0x7ffd061595e0 text: 0x7ffd061595f0 'stack area ?' 0x7ffd061595c0: e8 9a 15 06 fd 7f 00 00 58 97 75 70 02 00 00 00 ........X.up.... 0x7ffd061595d0: 50 94 75 70 b8 7f 00 00 48 96 15 06 05 00 00 00 P.up....H....... 0x7ffd061595e0: 00 01 02 03 04 00 00 00 3b 80 f7 00 00 00 00 00 ........;....... 0x7ffd061595f0: 48 65 6c 6c 6f 57 6f 72 6c 64 00 06 fd 7f 00 00 HelloWorld...... 0x7ffd06159600: f8 0f 3a 70 b8 7f 00 00 80 3d 39 70 b8 7f 00 00 ..:p.....=9p.... 0x7ffd06159610: 44 96 15 06 fd 7f 00 00 10 97 15 06 fd 7f 00 00 D...............  (途中省略) 0x7ffd0615af80: 65 20 25 73 20 25 73 00 4c 43 5f 54 49 4d 45 3d e %s %s.LC_TIME= 0x7ffd0615af90: 6a 61 5f 4a 50 2e 55 54 46 2d 38 00 4c 43 5f 4e ja_JP.UTF-8.LC_N 0x7ffd0615afa0: 41 4d 45 3d 6a 61 5f 4a 50 2e 55 54 46 2d 38 00 AME=ja_JP.UTF-8. 0x7ffd0615afb0: 58 41 55 54 48 4f 52 49 54 59 3d 2f 68 6f 6d 65 XAUTHORITY=/home 0x7ffd0615afc0: 2f 6e 69 69 64 61 2f 2e 58 61 75 74 68 6f 72 69 /niida/.Xauthori 0x7ffd0615afd0: 74 79 00 5f 3d 2e 2f 61 2e 6f 75 74 00 4f 4c 44 ty._=./a.out.OLD 0x7ffd0615afe0: 50 57 44 3d 2f 68 6f 6d 65 2f 6e 69 69 64 61 00 PWD=/home/niida. 0x7ffd0615aff0: 2e 2f 61 2e 6f 75 74 00 00 00 00 00 00 00 00 00 ./a.out......... Segmentation fault (コアダンプ) $ セグメンテーション例外を起こして死んだところがスタックの底です。荒っぽいやり方だけど、簡単にスタック領域を、ほぼ全域ダンプできますね。 つまり、今の時点でスタック領域のサイズは 0x7ffd0615b000 - 0x7ffd061595c0 = 0x1A40 = 6720 ですから、この場合、この時点で、 7KB 弱が有効な情報が残っているスタック領域です。
strike1217

2017/05/22 14:05

アドレスが大きい方が底に近くなり、アドレスが小さい方に伸びるという事ですよね?? 上記の例だと argv: 0x7ffd061595c0が最も底から遠いという事ですか??
rubato6809

2017/05/22 14:06

argv 変数より若いところがスタックのトップ(スタックポインタ rsp レジスタ が指している番地)みたいですね。
rubato6809

2017/05/22 14:08

上記の例だと argv: 0x7ffd061595c0が最も底から遠い? YES.
strike1217

2017/05/22 14:08

そうなんですか! 「アドレスが大きい方が底に近くなり、アドレスが小さい方に伸びるという事ですよね??」 という事であっているという事ですよね! ずっと逆だと思っていました。
rubato6809

2017/05/22 14:43 編集

スタックはアドレスの小さい方に伸びる・・・アセンブリ言語を経験した人にとって、言わずもがなの常識です。
strike1217

2017/05/22 14:44 編集

rubatoさんの場合、回答の方を見ると、iのアドレス < xのアドレスになっていますが、 私の環境では、gcc Linuxでやると、逆に iのアドレス > xのアドレスとなっています。 コンパイラが異なるからでしょうか?? Linuxでやっているんですか??
rubato6809

2017/05/22 14:55

Ubuntu (Debian Linuxベース)16.04だけど。言うまでもなく64bit版。繰り返すが、gccは5.4.0。 人はアドレスの値を読み間違えることがあるから、そちらの実行結果も貼り付けてみたら、どうか。
strike1217

2017/05/22 15:43

&i = 0x7fffc59d380c &x[0] = 0x7fffc59d3800, &x[1] = 0x7fffc59d3801, &x[2] = 0x7fffc59d3802, &x[3] = 0x7fffc59d3803, &x[4] = 0x7fffc59d3804, アドレスだけ載せますね
strike1217

2017/05/22 15:44

iのアドレス > xのアドレスになっていますね・・・
rubato6809

2017/05/22 21:16

そうだね。。。何が違うんだろう。 ソースファイルに何か違いは無いか?コンパイラのバージョン?コンパイルオプション?最適化で何か違いが出たのだろうか? 他に考えられる要因、、、う〜ん、ちょっと思いつきません。
rubato6809

2017/05/22 21:30

ただ、変数がスタック上(一般的にメモリ上)に、どんな風に格納されているか、ということはダンプして見るのは一つの手だということであって、配置の順序が違っても、ささいな違い、あるいは、こういう違いがあることがある、という事です。 もう少し頑張って、メモリダンプと合わせて、コンパイラが生成するアセンブリコードを調べると、スタックフレームがどうなってるか、見えてきます。
strike1217

2017/05/23 03:31

はい! ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問