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

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

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

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

Q&A

解決済

3回答

2427閲覧

C言語 初心者 リターンアドレスを変えたときの動きに不明点があるので教えてください。

kazuyakazuya

総合スコア193

C

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

0グッド

2クリップ

投稿2019/09/14 12:41

編集2019/09/14 14:04

C言語でリターンアドレスをいじって挙動を確認していたのですが
以下のコードでわからないところがあるのでお願いします。

c

1#include <intrin.h> 2#include <stdio.h> 3void* __stdcall f1() 4{ 5 puts(__FUNCTION__); 6 return _ReturnAddress();//返り値としてリターンアドレスを返す。 7} 8void* __stdcall f2(void* p) 9{ 10 puts(__FUNCTION__); 11 *(void**)_AddressOfReturnAddress() = p;//リターンアドレスをf1のものへ変える。 12 return 0; 13} 14 15int main() 16{ 17 void* p = f1();//ポインタpにf1のリターンアドレスを代入。 18 printf("リターンアドレスは・・・%p\n",p); 19 f2(p);//f2関数の引数にf1のリターンアドレスを指定。 20 return 0; 21}

実行すると

c

1f1 //f1が実行されて f1 を表示 200FE1DADf2// f1のリターンアドレス 300000000f2// f2のリターンアドレスをf1のリターンアドレスに変えたら・・・ 4

なぜ2回目の表示でリターンアドレスを代入したポインタpの
値が変わるのかが理解できません。

リターンアドレスはその関数の処理が終わったときに次に処理したい関数のアドレスを
指定するものですよね?
なら、1回目のポインタpへの代入以降
値は変わらないと思うのですが。

c

100FE1DADf2 200FE1DADf2

このようになることを期待したのですが・・・。
分からないので参考になるリンクまたは説明をお願いします。

c

1#include <intrin.h> 2#include <stdio.h> 3void* __stdcall f1() 4{ 5 puts(__FUNCTION__); 6 return _ReturnAddress(); 7} 8void* __stdcall f2(void* p) 9{ 10 puts(__FUNCTION__); 11 *(void**)_AddressOfReturnAddress() = p; 12 printf("f2関数内・・・%p\n",p); 13 return 0; 14} 15 16int main() 17{ 18 void* p = f1(); 19 printf("リターンアドレスは・・・%p\n",p); 20 f2(p); 21 return 0; 22} 23

c

1f1 2リターンアドレスは・・・00A61DAD 3f2 4f2関数内・・・00A61DAD 5リターンアドレスは・・・00000000 6f2 7f2関数内・・・00000000

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

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

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

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

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

maisumakun

2019/09/14 12:52

「初心者」がやるべきことではないのではないと思うのですが(なんのためにこれを実行しようとしましたか?)。
kazuyakazuya

2019/09/14 12:58

他のサイトでリターンアドレスについて質問したところ リターンアドレスがどういうものか理解できるように・・・ということで サンプルコードをいただきました。 そのコードの意味が分かってきたので 少しだけコードを変更したところ、今の不明点にいたります。
thkana

2019/09/14 13:32

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13213483518 とかそれ以降の流れですね。その情報無しで欲しい回答が得られそうに思いますか? もはや入門書のレベルを完全に超えているんですけど、せめて入門書を一通り終えてからいろいろ手を出そう、という話をしてませんでしたっけ?
kazuyakazuya

2019/09/14 13:36

一応やったのですが その入門書(苦しんで覚えるC)自体には 「リターンアドレス」 の説明がなかったです。 リターンアドレスについてぐぐったりしたのですが 出てくるのがバッファオーバーフローや 手紙とかのリターンアドレスだったりで うまく情報を集められなかったので質問しました。
guest

回答3

0

ベストアンサー

リターンアドレスはその関数の処理が終わったときに次に処理したい関数のアドレスを指定するものですよね?

違います。次に処理したい「関数」ではないです。機械語における「命令」の単位でアドレスは指定されます。

そもそもプログラムの流れを理解していないように見えます。
関数の中で自分自身のリターンアドレスを破壊するということは関数からまともに出られなくなるということです。
たぶん次のような実行の流れになっていると思います。4.3がポイントですが、きちんと理解して破壊していますか?

1 mainから開始する 2 p = f1()の行で、 2.1 関数f1に入り、まともに出る 2.2 f1の返り値(=f1のリターンアドレス)をpに代入する 3 printf()でそれを表示する 4 f2(p)の行で 4.1 関数に入る 4.2 printf()で引数の値を表示する 4.3 リターンアドレスを書き換えたのでまともに関数から出られず、2.2へ飛ぶ 2.2. f1の返り値のつもりでf2の返り値である「0」をpに代入する 3. printf()でそれを表示する 4. f2(p)の行で 4.1. 関数に入る 4.2. printf()で引数の値を表示する 4.3. リターンアドレスを書き換えたのでまともに出られず、「0」番地へ飛ぶ 5. 例外が発生し、プログラムが強制終了する

投稿2019/09/14 20:01

ikadzuchi

総合スコア3047

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

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

guest

0

なぜ2回目の表示でリターンアドレスを代入したポインタpの
値が変わるのかが理解できません。

f1関数の_ReturnAddress()はmain関数上の「関数の戻り値を変数pに代入する」命令のアドレスを返します。

f2関数で*(void**)_AddressOfReturnAddress() = p;を実行により、f2関数から戻るアドレスが「関数の戻り値を変数pに代入する」命令のアドレスに変わります。
関数f2は戻り値に0を渡しているので戻った後、その値がpに入ります。

投稿2019/09/14 13:25

nomuken

総合スコア1627

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

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

guest

0

まずはアセンブルリストを出して、どういう動作をするのか見てみればどうでしょうか。

投稿2019/09/14 13:02

y_waiwai

総合スコア87774

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

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

kazuyakazuya

2019/09/14 13:05

ありがとうございます。 そちらの方面もやってみます。
y_waiwai

2019/09/14 13:08

人に聞くよりもさきにそっちを調べようよ。
kazuyakazuya

2019/09/14 13:10

そもそも、そのような発想がなかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問