Visual Studio 2010 - сегмент данных и память стека одинаковы

Я выяснил, что постоянный литерал get помещается в сегмент данных программы (из SO) и доступен только для чтения, и, следовательно, строка " s[0] = 'a' " может вызвать ошибку, которая действительно происходит, когда я раскомментировал эту строку и побежал. Однако, когда я посмотрел в окно памяти в MS VS, все переменные были помещены в память. Мне любопытно, как они (компилятор) обеспечивают доступ только для чтения к 's'?

#include <iostream>

int main(void)
{
      char *s = "1023";
      char s_arr[] = "4237";
      char *d = "5067";
      char s_arr_1[] = "9999";
      char *e = "6789";
      printf("%c\n", s[0]);
//      s[0] = 'a'; This line would error out since s should point to data segment of the program
      printf("%s\n", s);
      system ("pause");
}

0x002E54F4  31 30 32 33 00 00 00 00 34 32 33 37 00 00 00 00  1023....4237....
0x002E5504  35 30 36 37 00 00 00 00 39 39 39 39 00 00 00 00  5067....9999....
0x002E5514  36 37 38 39 00 00 00 00 25 63 0a 00 25 73 0a 00  6789....%c..%s..
0x002E5524  70 61 75 73 65 00 00 00 00 00 00 00 43 00 3a 00  pause.......C.:.

Редактировать 1: Обновление значения, хранящегося в s_arr (которое должно быть помещено в пространство стека), чтобы было ясно, что оно находится рядом со строковыми константами.

Изменить 2: Поскольку я вижу ответы о доступе ro/rw на основе страниц, здесь адрес.. 0x...4f4 - это rw 0x...4fc - это ro, и снова 0x...504 - это rw. Как они достигают этой детализации? Кроме того, поскольку каждая страница может занимать минимум 4 КБ, можно утверждать, что 0x4fb может быть последним адресом предыдущей страницы ro. Но теперь я добавил еще несколько переменных, чтобы показать, что все они размещены в памяти непрерывно, а степень детализации - на каждые 8 ​​байтов. Вы могли бы сказать, так как страницы на уровне 4k, как вы упомянули,

3 ответа

Решение

Я не знаю, что заставило вас думать, что ваш пример показывает модифицируемую память рядом с неизменяемой памятью. О какой гранулярности вы говорите? У тебя дамп памяти ничего подобного не показывает.

Строка "4237" что вы видите в своем дампе памяти не ваше s_arr, Тот "4237" что вы видите строковый литерал только для чтения, который использовался как инициализатор для s_arr, Этот инициализатор был скопирован в s_arr, Между тем, фактическая s_arr находится где-то еще (в стеке) и является совершенно изменяемым. Это содержит "4237" так же (как и его первоначальное значение), но это совершенно другое "4237", который вы не видите в своем дампе памяти. Попросите вашу программу напечатать адрес s_arr и вы увидите, что это далеко не тот диапазон памяти, который вы сбросили.

Опять же, ваше утверждение о "0x...4f4 равно rw 0x...4fc равно ro и снова 0x...504 равно rw" совершенно неверно. Все эти адреса доступны только для чтения. Ни один из них не для чтения и записи. Там нет никакой "детализации" там вообще.

Помните, что такая декларация

char s_arr[] = "4237";

действительно эквивалентно

const char *unnamed = "4237";
char s_arr[5];
memcpy(s_arr, unnamed, 5);

В вашем дампе памяти, вы смотрите на это unnamed адрес из моего примера выше. Эта область памяти доступна только для чтения. Ваш s_arr находится в совершенно другой области памяти, которая является чтение-запись.

Поскольку были представлены 32-битные платформы, все помещается в один и тот же сегмент (это не совсем так, но проще думать, что это так. Существуют незначительные предостережения, требующие нескольких страниц для объяснения, и они относятся к дизайну операционной системы),

32-разрядное адресное пространство разделено на несколько страниц. Intell позволяет назначать биты RO с детализацией страницы. Отладчики отображают только 32-битный (64-битный) адрес, который технически является смещением в сегменте. Это смещение можно назвать просто адресным. Там не будет никакой ошибки в этом.

Тем не менее, линкеры называют разные области памяти сегментами. Эти сегменты не имеют ничего общего с сегментами памяти Intel. Сегменты линкера (код, данные, стек и т. Д.) Загружаются в страницы diffrenet. Эти страницы получают разные атрибуты (RO/RW, разрешение на выполнение и т. Д.).

Блок памяти, который вы показываете, является областью, в которой хранятся строковые константы (как вы можете видеть, все 4 значения находятся рядом друг с другом). Эта область помечена как доступная только для чтения. В Windows каждый блок памяти (страница) размером 4 КБ может иметь свои собственные атрибуты (чтение / запись / выполнение), поэтому даже 2 смежных местоположения могут иметь разные флаги доступа.

Область, в которой находятся переменные, находится в другом месте (в вашем случае это стек). Вы можете увидеть это, проверив значение &s непосредственное окно (или окно просмотра).

Другие вопросы по тегам