93980


後述のコードを実行すると、以下のような結果になりました。

私は基本的なメモリレイアウトとしてはmain関数やfunc関数を下記のように宣言してアドレスを出力した場合、stack領域に配置されるため、変数xと近いアドレスが出力結果として得られると予想しましたが、結果としてはグローバル変数として宣言し、bssセグメントに配置されるであろう変数jと限りなく近いアドレスにそれらは配置されることになることがわかりました。  
メモリレイアウトは環境によって異なることは承知しているのですが、自作関数がstack領域でないメモリに配置されることは可能性としてあるのでしょうか。

**実行結果:**

[code]

    0x1001a3edc
    0x1001a3ee0
    0x1001a8000
    0x16fc5f4dc
    0x6000000b0030
    
[/code]

**対象のコード:**

[code]

    #include <stdio.h>
    #include <stdlib.h>
    
    void func() {
        ;
    }
    
    int j;
    
    int main() {
        int x = 1;
        printf("%p\n", func);
        printf("%p\n", main);
        printf("%p\n", &j);
        printf("%p\n", &x);
        void *ptr = malloc(1);
        printf("%p\n", ptr);
    }
    
[/code]


CC BY-SA 4.0
2023-02-24T10:13:54.903
93977
2023-02-24T13:31:24.483
2023-02-24T12:26:34.883
4236
55503
question
c
理論で学んだメモリレイアウトが実際にアドレスとして出力すると期待通りにならない


関数をスタック領域に配置する実行環境があると想定するする根拠を教えてください。  
Windows, Unix, Linux のどれもそうなっていないと思います。

コード領域とデーター領域とがソースコードをコンパイルなりアッセンブルした時に翻訳系が  
割り付けることはお分かりですか？  
リンカーで実行ファイルにしたときにもデーター領域とコード領域とにまとめます。  
そうしないと再配置（リロケーション）の計算が面倒になるからでしょう。

コード領域の大きさがスタック領域の大きさより小さいという保証があるのなら、無理をして  
スタック領域の中にコード領域を押し込めることは可能かもしれませんが、その分スタックの使用可能量が  
減ることになりませんか？


CC BY-SA 4.0
2023-02-24T12:24:50.587
93979
2023-02-24T12:24:50.587
43029
93977
answer


現代的な実行環境では通常はメモリはその用途ごとに属性をつけて管理され、実行可能なコード (C 的に言えば関数) は独立したセクションに配置されます。
逆に言えば他のセクションは実行できないように管理されています。

関数がスタックに配置されるということは普通はないです。
メモリの分離があまりされていない素朴な実行環境では結果的にかぶることもあるかもしれませんが、関数を意図的にスタックに配置することは古い環境でもまずないです。
そういう資料を読んだのだとしたらそれは誤った記述 (もしくは質問者の誤解) です。

例えば私の環境での実行結果はこうです。

[code]

    00007ff6b1fe1450
    00007ff6b1fe1457
    00007ff6b1fed030
    0000001a5f1ffab4
    0000020ecb2b1400
    
[/code]

メモリ配置はこうです。

[![メモリ配置](https://i.stack.imgur.com/avRo1.png)](https://i.stack.imgur.com/avRo1.png)

実行可能コードが配置される `text` セクションと未初期化のデータが配置される `bss`
セクションはそれほどはなれていないませんので結果的に質問者の事例と似た感じですね。

スタックやヒープは後から伸ばしたりすることもあるので離れた位置に配置されています。


CC BY-SA 4.0
2023-02-24T12:30:48.403
93980
2023-02-24T12:30:48.403
3364
93977
answer


>
> main関数やfunc関数を下記のように宣言してアドレスを出力した場合、stack領域に配置されるため、変数xと近いアドレスが出力結果として得られると予想

> 自作関数がstack領域でないメモリに配置されることは可能性としてあるのでしょうか。

今どきはマルチスレッドが広く使われていて、OSもそれを前提に設計されています。そしてstackはスレッド毎に用意する必要があります。  
ということを知っていると…

stackの近くに存在するのはせいぜい隣のスレッドのstackでしょう。

それとは別に、[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)というものもあり、OSによっては自作関数がランダムに配置される場合もあり得ます。

自作関数の配置場所やstackの配置場所はどちらも意識すべきではありません。


CC BY-SA 4.0
2023-02-24T12:41:34.320
93981
2023-02-24T12:41:34.320
4236
93977
answer


本題とは無関係ですが、gcc の拡張機能([Nested Functions (Using the GNU Compiler Collection
(GCC))](http://gcc.gnu.org/onlinedocs/gcc/Nested-
Functions.html))を使うと、(ローカル変数なので)スタックに置かれることになります。

[code]

    #include <stdio.h>
    #include <stdlib.h>
    
    int j;
    
    int main() {
      auto void func(); // declaration, optional
      void func() {     // definition
        ;
      }
      int x = 1;
      printf("%p\n", func);
      printf("%p\n", main);
      printf("%p\n", &j);
      printf("%p\n", &x);
      void *ptr = malloc(1);
      printf("%p\n", ptr);
    }
    
[/code]

[code]

    $ gcc --version
    gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
    
    $ gcc -Wall -Wextra -g test.c -o test && ./test
    0x7ffe37cadaf0
    0x558170386198
    0x558170389014
    0x7ffe37cadae4
    0x5581722396b0
    
[/code]


CC BY-SA 4.0
2023-02-24T13:31:24.483
93983
2023-02-24T13:31:24.483
47127
93977
answer