Различные сегменты могут разрушаться друг с другом - PullRequest
0 голосов
/ 17 июня 2019

Когда мы кодируем, то мы даем разным сегментным регистрам одно и то же значение, в этом случае два разных сегмента могут мешать друг другу, и могут возникнуть проблемы. Например, в приведенном ниже условии.

MOV AX, CS
MOV SS, AX
ASSUME SS: DOSGROUP 

, как указано выше, в строке 1 мы перемещаем CS в AX. Сразу после этого мы AX к SS. Это означает, что в этот момент регистры CS и SS содержат одно и то же значение или одно и то же место в памяти. Разве это не правда, что при дальнейшем кодировании содержимое CS будет разрушаться вместе с содержимым SS.

Ответы [ 2 ]

3 голосов
/ 17 июня 2019

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

Наличие двух сегментных регистров с одним и тем же значением означает, что одно и то же смещение X может использоваться с обоими для доступа к одним и тем же данным.
Это удобно, если мы не хотимчтобы указать ассемблеру, как считать смещение для разных сегментов.
Если мы напишем программу на ассемблере наивно, нам не хватит информации о сегменте для ассемблера, который будет считать нашу программу отдельным сегментом кода.Таким образом, ассемблер будет использовать один и тот же счетчик смещения для и данных и кода, но во время выполнения эти две области являются доступами с различным сегментом (а именно DS и CS), если вы не переопределите его для каждой загрузки / сохранения.
Если свойство выше не было истинным, смещения данных, сгенерированные ассемблером, не будут совпадать, если загрузчик загрузил программу.

Это также полезно при получении указателя на функции или обработке данных в стеке через указатель (т. Е. Без фиксированного смещения от bp), он по сути преобразует каждый указатель в ближний указатель.
Итаксмещение переменной фактически становится адресом переменной, без дальнейшей необходимости также учитывать сегмент.Это облегчает рассуждение об адресах / смещениях, потому что теперь, если переменная имеет смещение X, это единственное смещение, о котором мы должны беспокоиться, X - это то же самое, что мы используем CS, DS или SS.
Таким образом, X сопоставляется 1-1 с его переменной var, если мы должны были принимать во внимание сегменты, каждая переменная может иметь до 64Ki / 16 смещений, и этот набор не отделяется отнабор смещений другой переменной (т. е. смещение X может обозначать две разные переменные при использовании с двумя разными сегментами), и поэтому указатели должны были быть далеко.
Поскольку у нас есть только несколько эффективно свободных регистров сегментов, далекоуказатели (помимо удвоения размера указателя) оказывают большое давление на стратегию размещения регистров.

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

Если у нас нет нескольких сегментов для каждого типа данных (данные / стек, код), используяотдельные сегменты увеличивают адресуемую память бесплатно, но при инициализации несколько строк (если мы не берем указатели на функции).
Наличие одного и того же сегмента для стека и данных полезно при передаче указателей на структуры в стеке,Исполняемые файлы

DOS .com являются примером программ, в которых CS, DS и SS имеют одинаковое значение.Исполняемые файлы DOS .exe часто собираются / компилируются для небольшой модели памяти, где у нас есть только сегменты кода (CS) и данных (DS, SS).
Однако они могут обрабатывать другие модели памяти,в том числе огромный, где мы можем иметь несколько сегментов для типа данных (код, стек, данные).

Программирование с несколькими сегментами подвержено ошибкам, поэтому 32-разрядные ОС перестали его использовать, а 64-разрядные ОС не могут его использовать (но ограниченным образом).
Однако сегменты также полезны,они могут создать удобный вид в памяти, особенно при доступе к регионам MMIO и ISA.

Эту стену текста трудно разобрать, если у вас недостаточно (болезненный?) Опыт работы с сегментами, я советую начать с работающей программы и намеренно навредить себе, перемещая данные в (излишне) разделенные сегменты.
Только помните, как логические адреса (сегмент: смещение) переводятся в линейные адреса (сегмент * 16 + смещение).

0 голосов
/ 18 июня 2019

Я бы хотел разделить свой ответ на две части.

Часть 1

Это означает, что в этот момент регистры CS и SS содержат одно и то же значение или одну и ту же ячейку памяти ...

В 16-разрядных программах x86 сегменты не описывают области памяти, но описывают диапазоны областей памяти:

«Идеализированный» 16-разрядный процессор может работать только с 64 КБ памяти. Для работы с большим объемом памяти, чем 64 КБ, 8086-совместимые процессоры имеют сегменты:

Значение регистров сегмента описывает диапазон памяти размером 64 КиБ, где должен работать процессор. Таким образом, 16-разрядная программа может (только) получать доступ к 64 КБ памяти, но, изменяя значение регистров сегмента, она может выбрать, какие 64 КБ из 1 МБ памяти должны быть доступны. Это означает, что программа может эффективно обращаться к 1 МБ памяти (а не только к 64 КБ), изменяя значения регистров сегмента.

Конечно, код и различные типы данных могут находиться в одном и том же диапазоне памяти 64 КиБ. (В случае компьютера с только 64 КБ памяти (например, IBM PCjr 1982 года) это даже очевидно.)

В этом случае CS и SS имеют одно и то же значение, поскольку код (регистр CS) и стек (регистр SS) находятся в одном и том же диапазоне памяти 64 КиБ . .

Но есть разница между "одним и тем же диапазоном памяти" (который содержит много разных областей памяти) и "одним и тем же местом памяти".

Часть 2

Как мы можем выполнить две операции ... используя одну и ту же ячейку памяти.

Давайте изменим ваш пример и будем использовать пары регистров SS:SP и ES:DI вместо регистров CS и SS. Эти пары фактически описывают область памяти, а не диапазон памяти.

Что произойдет, если SS:SP и ES:DI имеют одно и то же значение?

Ответ: Ничего.

ЦП использует SS:SP для вычисления места в памяти для операций стека (например, push или pop) и ES:DI для операций записи в строку (например, stos или movs).

Поскольку ЦП не выполняет две операции одновременно, нет проблем, если для обоих видов операций указана одна и та же ячейка памяти.

Однако вы должны позаботиться о том, чтобы ничего глупого не случилось. Пример: * 1 063 *

push bx
; Let's say SS:SP and ES:DI contain the same value here
stosw
pop bx

Используя инструкцию stosw, вы уничтожите данные, которые у вас есть push, используя инструкцию push, поскольку SS:SP и ES:DI указывают на одну и ту же ячейку памяти.

CPU не заботится об этом. Если процессор получает команду перезаписать стек, он перезапишет стек.

Ваша задача как программиста - избежать этого.

Но на самом деле у вас точно та же проблема с каждым языком программирования. В C, C ++, C # или Java вы можете допустить следующую ошибку:

for(i = 0; i < 5; i++)
{
    for(i = 0; i < 10; i++)
    {
        ...
    }
}

... и не понимаю, почему внутренний цикл выполняется 10 раз вместо 50 раз.

...