Как дно стека определяется?

Стек является непрерывным блоком памяти, содержащей данные. Регистр назвал точки указателя вершины стека (SP) к вершине стека. Дно стека в фиксированном адресе.

Как дно стека фиксируется ядром?

10
задан Mask 30 March 2010 в 01:47
поделиться

3 ответа

Это будет частью реализации самого стека. Если вы реализуете стек (например) на C, вы можете сохранить указатель стека и текущее количество элементов. Или указатель стека вместе с основанием стека, что-то вроде:

typedef struct {
    int *sp_empty;
    int *sp;
    int *sp_full;
} tIntStack;

tIntStack stk;

// Initialise 20-element stack.
stk.sp = stk.sp_empty = malloc (sizeof(int) * 20);
stk.sp_full = &(stack[20]);

// Push a value x, detecting overflow.    
if (stk.sp == stk.sp_full) { error here}
*(stk.sp) = x;
stk.sp++;

// Pop a value x, detecting underflow.    
if (stk.sp == stk.sp_empty) { error here}
stk.sp--;
x = *(stk.sp);

Если вы говорите о стеке ЦП (адреса возврата и т. Д.), Вы можете обнаружить опустошение стека в силу того факта, что произошел сбой. Плохо.


Например, в былые времена, когда процессоры были ограничены адресным пространством 64 КБ, процессоры обычно тестировали память до тех пор, пока не находили первый байт, который читается не так, как только что был записан (в процессе загрузки). Это был первый байт за пределами реальной физической памяти, поэтому они установили SP равным единице ниже этого.Конечно, некоторые (небольшое количество) машин имели 64 КБ физической ОЗУ, поэтому просто установите SP в верхнюю часть адресного пространства.

В настоящее время процесс в многозадачных операционных системах с огромным адресным пространством, виртуальной памятью немного сложнее, но все же сводится к следующему (в большинстве случаев):

  • Адресное пространство выделяется для процесс.
  • SP устанавливается где-то в этом адресном пространстве.
  • Процесс выполняется.

На этом этапе вы, вероятно, сами по себе в том, что касается ядра. Его ответственность прекращается в точке, где запускается ваш код, кроме переключения задач и предоставления услуг по запросу, но это не имеет отношения к вашему стеку. Если ваш код с ошибками переполняется или не заполняется стеком, это ваша проблема .

Ядро может проверять ваш SP при переключении задач, чтобы убедиться, что вы сделали что-то не так, но это ни в коем случае не гарантируется. Он также может использовать аппаратную защиту памяти для обнаружения потери значимости (если стек находится наверху выделенного вами адресного пространства). Но опять же, это полностью зависит от используемого ядра.

1
ответ дан 4 December 2019 в 02:25
поделиться

Я предполагаю, что вы имеете в виду «зафиксировано в пространстве памяти процесса», а не «зафиксировано в общей памяти». Вы можете посмотреть, где находится дно стека в любой новейшей системе Linux, выполнив поиск строки вроде

bfbce000-bfbe3000 rw-p bffeb000 00:00 0          [stack]

в выводе cat / proc / / maps . В этом случае нижняя часть стека имеет адрес 0xbffeb000 . В моей системе все основания стека, кажется, попадают в один из bffca000 bffcb000 bffdd000 bffe0000 bffe4000 bffe6000 bffeb000 (после прохождения через ~ 200 процессов).

Я предполагаю, что эти значения присваиваются глубоко в ядре, где бы процессы не были созданы впервые.

0
ответ дан 4 December 2019 в 02:25
поделиться

Я набрал более длинный ответ, но он бессвязный, поэтому вот более короткий ...

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

Итак, операционная система создает отображение в виртуальной памяти для стека и назначает указатель стека старшему адресу этого блока. В стеке с предварительным приращением, где указатель стека декрементируется перед разыменованием, начальный указатель стека фактически является адресом после последнего адреса в отображенном пространстве.

Когда процесс пытается поместить что-то в стек, это приводит к доступу к этой области памяти, которой не сопоставлено никакое физическое ОЗУ. Это вызывает сбой страницы, в результате чего ОС выбрасывает наименее используемую (или близкую к ней) страницу ОЗУ в диск подкачки или файл подкачки и переназначает страницу физического ОЗУ странице стека, к которой осуществляется доступ. Теперь, когда есть физическая ОЗУ, ОС возвращается, и процесс продолжается, помещая отправленные данные в память стека.

Что произойдет, если вы выбросите все из стека, а затем попытаетесь открыть его снова? Это последнее всплывающее сообщение, когда указатель стека находится в своем начальном значении, приводит к доступу к адресу виртуальной памяти, который не сопоставлен со стеком. Это вызывает ошибку сегментации, что означает, что процесс пытался получить доступ к памяти, которую он никогда не выделял. ОС в ответ завершает процесс и очищает все, что может.

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

7
ответ дан 4 December 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: