14344


特に困っているわけではないのですが、素朴な疑問として、  
Cygwinのg++で次のコードを実行すると、Cygwinだけが毎回同じアドレスを表示します。  
そもそもOSは仮想アドレッシングをしていて、  
実際の物理アドレスとは違う値を表示しているのは理解していますが、  
Windows(MSVC)/CentOS(g++)/Ubuntu(g++)で下記コードを実行すると  
毎回違うアドレスを表示するのですが、  
Cygwinのg++だけ何度実行しても同じアドレスを表示します。  
どうしてこのような結果になるのかご教示いただけないでしょうか。  
さらに不思議なことにprintf("%p\n", ...)の結果が  
Cygwinでのみ6桁で表示されるのですが(他は8桁、CentOSの64bit版の場合は12桁)、これもなぜなのかわかりません。

[code]

    #include <cstdio>
    
    int main()
    {
        int c = 1;
        int *a;
        int &b = c;
        a = &c;
    
        printf("変数に格納されている値\n");
        printf("a: %d\n", *a);
        printf("b: %d\n", b);
        printf("c: %d\n", c);
        printf("アドレス\n");
        printf("a: %p\n", a);
        printf("b: %p\n", &b);
        printf("c: %p\n", &c);
    
        getchar(); // 一時停止
    
        return 0;
    }
    
[/code]

実行結果例(MSVC)

[code]

    変数に格納されている値
    a: 1
    b: 1
    c: 1
    アドレス
    a: 007EF940
    b: 007EF940
    c: 007EF940
    
[/code]

※アドレスの値の先頭に0xが付くなどはどうもコンパイラ依存のようです。  
プログラム毎に独立したメモリ空間を使うため、毎回アドレスが変わると思っていたのですが、  
Cygwinのみが同じアドレスを指します。

ちなみに、`static int c = 1;`とすればどの環境でも毎回、アドレスは同一になります。  
ひょっとするとこのような質問はstackoverflow的には好ましくないのかもしれません……。

**回答を得た後の追記**  
**_質問する時点では知らなかったのですが、セキュリティ対策がなしの設定ではどのコンパイラ(もっと正確にいうと処理系)も毎回同じアドレスになる、というのが普通です。Cygwin以外が本当は通常と異なる動きをしていました（ASLR等のセキュリティ対策がON）_**  
また、私自身の質問が混乱した記述になっていますが、同じアドレスから通常は始まる理由は[アドレス空間](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E7%A9%BA%E9%96%93)によると、

>
> ユーザ空間または「ユーザー仮想アドレス空間」はユーザープロセスの動作するアドレス空間である。コンピュータシステム上で動作する各プロセスは、それに対応するデータとコードを持ち、実行中にはそれらがユーザ空間上にロードされる。ユーザ空間はプロセス毎に割り当てられ、それぞれのアドレス範囲は同じである。従って、仮想記憶方式のオペレーティングシステムでは、ユーザープログラムのコードやデータは同じアドレスから開始されるようになっていることが多い。

とのことです。


CC BY-SA 4.0
2015-08-12T18:25:38.463
14337
2019-03-27T09:01:57.430
2019-03-27T09:01:57.430
4236
7744
question
c++ cygwin
Cygwinのg++で毎回、実行時に変数のアドレスが一緒になるのは何故？


まず `%p` は「アドレスを人が読みやすい形に文字化する」機能ですが、  
その詳細までは決まっていませんので処理系が任意に決めていいことになっています。  
各処理系がなぜそういう形式を採用したのかは処理系実装者に訊いてみる必要がありそうです。

次に、このプログラムが表示する３つの `%p` はすべて同一の変数 `c` へのポインタですが、  
そこに疑問は無いわけですね？  
\- １回の実行結果の３つの値は同じ (何度実行しても、その１回では同じ)  
\- コンパイルするたび、あるいはコンパイルせず実行すると、そのたび値が違う  
という理解でよいですか？

今ウチには MSVC がないので cygwin-x86_64 になっちゃいますが  
\- コンパイルせず、同一の実行形式ファイルを複数回実行すると、同じ値になるのが普通  
\- コンパイルしなおすと（特にコンパイルオプションを変更すると）違う値になるのが普通  
だと思います。

ウチでの検証結果は  
`g++ hoge.cpp` `./a.exe` とすると 0x22cb0c と表示される  
`g++ -O hoge.cpp` `./a.exe` とすると 0x22cb1c と表示される  
でした。

OS がプログラムを起動する際のスタック初期値は同じなので、  
同じプログラムを起動するなら `c` も同じアドレスに割り振られる、のが普通です。

MSVC Ubuntu 等で違う挙動をするとしたらセキュリティ対策かな・・・  
同一のプログラムであってもわざと違う挙動をさせることで、  
クラッカーによる分析を困難にしたい・・・のかな？  
とりあえずオイラの手元に無いので検証してないから妄想レベルです。  
他の人の検証を求む。


CC BY-SA 3.0
2015-08-12T20:53:32.950
14338
2015-08-12T20:53:32.950
8589
14337
answer


ふと思い出したので、

質問文の追記にもありますが、従来、同じ操作をすれば同じアドレスが得られるのが自然な結果です。しかし、同じアドレスとなると攻撃者はアドレス指定で攻撃が可能となってしまうため、セキュリティを考慮して多少のパフォーマンスを犠牲にしてあえてランダム化するのが一般的となっています。

その上で、cygwinが同じアドレスとなるとは、ランダム化に対応していないためではありませんでした。目的を持ってあえてアドレスを一致させています。[Cygwin](https://ja.wikipedia.org/wiki/MinGW#Cygwin%E3%81%A8%E3%81%AE%E6%AF%94%E8%BC%83)は

>
> Windows上に、Linuxや他のUNIXシステムに見られるような、完全なPOSIX層を提供することを目標にしており、互換性のために必要であれば性能も犠牲にしている。

と説明されている通りで、その中に特に大きな役割を持つのが[`fork`](https://ja.wikipedia.org/wiki/Fork)システムコールがあります。

UNIXシステムでは子プロセスを起動する際、`fork`を使用してプロセスのコピーを作成し、コピー側は`exec`で新たな実行ファイルをロード、実行を開始します。しかし、Windowsの場合、`CreateProcess`で直接、子プロセスを作成してしまうため、`fork`のようなプロセスのコピーを作成できません。  
苦肉の策として、Cygwinは`CreateProcess`で子プロセスを作成し、親プロセスと同じメモリ状態を構築し、`fork`相当を実現しています。当然、このアプローチで実現するためには全てのDLLの読み込みアドレスを一致させ、各種ランダム化を無効化する必要があります（でなければ各種ポインターの値が異なってくるため不整合が生じます）。

* * *

追記前の旧投稿

[ASLR;
アドレス空間配置のランダム化](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E7%A9%BA%E9%96%93%E9%85%8D%E7%BD%AE%E3%81%AE%E3%83%A9%E3%83%B3%E3%83%80%E3%83%A0%E5%8C%96)に対応しているかどうかです。cygwinがASLRに未対応というだけでしょう。  
例えばWindows(MSVC)でも毎回違うアドレスと書かれていますが、それは[リンカーオプション
/DYNAMICBASE](https://msdn.microsoft.com/ja-
jp/library/Ff820372\(v=VS.120\).aspx)を指定した場合です。


CC BY-SA 4.0
2015-08-12T21:04:08.240
14339
2019-03-27T08:39:45.950
2019-03-27T08:39:45.950
4236
4236
14337
answer


Cygwin については不明ですが、Linux OS で stack pointer や base pointer
の値が実行ごとに変化するのは、ASLR(Address Space Layout Randomization)が有効になっているからだと思います。

# ASLR については調べれば分かることですので、ここでは説明を省きます。

ASLR の設定は変更可能です。

[code]

    $ cat /proc/sys/kernel/randomize_va_space
    2
    
[/code]

デフォルトは有効ですが、"0" を設定すると無効になります。

[code]

    $ sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"
    $ cat /proc/sys/kernel/randomize_va_space
    0
    
    $ ./example
        :
    アドレス
    a: 0xbffff668
    b: 0xbffff668
    c: 0xbffff668
    
    $ ./example
        :
    アドレス
    a: 0xbffff668
    b: 0xbffff668
    c: 0xbffff668
    
[/code]


CC BY-SA 3.0
2015-08-13T01:40:07.350
14344
2015-08-13T01:40:07.350
14337
answer


お二方の回答を受けて、ASLR有効化、無効化の方法を書きます。  
最近のOSはどれもたいてい既定でASLRが有効になっているようです。  
CygwinのGCCでASLRを有効化する方法です。

[code]

    $ g++ -Wl,--dynamicbase -Wl,-pie -o foo.exe foo.cpp
    
[/code]

ここが参考になりました。  
<https://security.stackexchange.com/questions/24444/what-is-the-most-hardened-
set-of-options-for-gcc-compiling-c-c>

また、逆に通常のLinuxでASLRを無効化する方法は既にargusさんが記載済みです。  
MSVCでASLRを無効化する場合は次のようにします。

[code]

    プロジェクトのプロパティページ > 構成プロパティ > リンカー > 詳細設定 > ランダム化されたベースアドレス   
    いいえ (/DYNAMICBASE:NO)
    
[/code]

に設定したうえでコンパイルします。  
<https://msdn.microsoft.com/ja-jp/library/Bb384887%28v=VS.120%29.aspx>


CC BY-SA 3.0
2015-08-14T01:20:52.980
14403
2015-08-15T19:02:51.317
2017-03-17T10:46:11.453
-1
7744
14337
answer