Структура виртуальной памяти процесса Linux выглядит следующим образом:
(Источник: Википедия, Дугкт .)
Процесс делится на разные сегменты памяти, в зависимости от того, как вы распределяете память. В Википедии есть хорошее объяснение того, для чего каждый из них.
Давайте пройдемся по программе, строка за строкой.
Строки 1-2: объявить 2 указателя, которые хранятся в стеке.
Строка 3: выделить 100 байтов в куче. Сделайте точку p1 на это. Другими словами: p1 - указатель (находится в стеке) на часть памяти (находится в куче).
Строка 4: скопировать строковый литерал (хранящийся в текстовом разделе) в часть памяти (расположенную в куче).
Строка 5: возврат. Это освобождает место для указателей, но не освобождает то, на что они указывают. Область памяти, на которую указывает p2, не освобождается, поэтому происходит утечка памяти. (Хотя программа заканчивается, поэтому здесь это не имеет значения.)
Код, который реализует strcpy - я полагаю, это в разделе DLL.
Краткий ответ: «текстовый раздел».
Полный ответ: «Это зависит от настроек вашего компилятора».
Допустим, вы статически связываете свою программу:
$ gcc -static test.c
$ ./a.out & pmap $!
0000000000400000 4K r---- a.out
0000000000401000 492K r-x-- a.out
000000000047c000 140K r---- a.out
00000000004a0000 24K rw--- a.out
00000000004a6000 4K rw--- [ anon ]
00000000007df000 140K rw--- [ anon ]
00007ffc6031b000 132K rw--- [ stack ]
00007ffc60358000 8K r---- [ anon ]
00007ffc6035a000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
Вторая строка, 0000000000401000 492K r-x-- a.out
- текстовый раздел. Обратите внимание, что она довольно большая для нашей 5-строчной программы. Это потому, что мы помещаем библиотеки, которые мы используем, в наш текстовый раздел.
С другой стороны, вы можете связать его динамически:
$ gcc test.c
$ ./a.out & pmap $!
[1] 5637
5637: ./a.out
0000555943977000 4K r---- a.out
0000555943978000 4K r-x-- a.out
0000555943979000 4K r---- a.out
000055594397a000 4K r---- a.out
000055594397b000 4K rw--- a.out
00005559442ca000 132K rw--- [ anon ]
00007f3af067b000 136K r---- libc-2.27.so
00007f3af069d000 1304K r-x-- libc-2.27.so
00007f3af07e3000 300K r---- libc-2.27.so
00007f3af082e000 16K r---- libc-2.27.so
00007f3af0832000 8K rw--- libc-2.27.so
00007f3af0834000 16K rw--- [ anon ]
00007f3af0838000 8K rw--- [ anon ]
00007f3af085e000 4K r---- ld-2.27.so
00007f3af085f000 120K r-x-- ld-2.27.so
00007f3af087d000 32K r---- ld-2.27.so
00007f3af0885000 4K r---- ld-2.27.so
00007f3af0886000 4K rw--- ld-2.27.so
00007f3af0887000 4K rw--- [ anon ]
00007fff10f99000 132K rw--- [ stack ]
00007fff10fc2000 8K r---- [ anon ]
00007fff10fc4000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
Обратите внимание на две вещи: наш текстовый раздел (0000555943978000 4K r-x-- a.out
) теперь крошечный. Также мы можем видеть, что libc загружен в отдельный раздел памяти. (Диаграмма, которую я показал выше, скрывает эту деталь - более полная диаграмма здесь: https://unix.stackexchange.com/questions/466443/do-memory-mapping-segment-and-heap-grow-until-they-meet-each-other)