Попов И.И., Матвеев А.А., Максимов Н.В. Архитектура электронно-вычислительных машин и систем (2004) (1186255), страница 93
Текст из файла (страница 93)
Если, например, X описанокак имя переменной размером в слово:X DW 999и если надо записать в байтовый регистр AH значение только первогобайта этого слова, тогда воспользоваться командойMOV AH,Xнельзя, т.к. ее операнды имеют разный размер. Эту команду следуетзаписать несколько иначе:MOV AH,BYTE PTR XЗдесь конструкция BYTE PTR X означает адрес X, но ужерассматриваемый не как адрес слова, а как адрес байта. (Напомним, чтос одного и того же адреса может начинаться байт, слово и двойноеслово; оператор PTR уточняет, ячейку какого размера мы имеем в виду.)И еще одно замечание.Еслив символьной команде,оперирующей со словами, указан непосредственный операнд размером вбайт, как, например, в командеMOV AX,80h475то возникает некоторая неоднозначность: что будет записано в регистрAX - число 0080h (+128) или 0FF80h (-128)? В подобных ситуацияхассемблер формирует машинную команду, где операнд-байт расширендо слова, причем расширение происходит со знаком, если операнд былзаписан как отрицательное число, и без знака в остальных случаях.Например:MOV AX,-128 ; => MOV AX,0FF80h (A:=-128)MOV AX,128 ; => MOV AX,0080h (A:=+128)MOV AX,80h ; => MOV AX,0080h (A:=+128)СегментированиеСегменты памяти.
Сегментные регистры. Первые модели I80Х86имели оперативную память объемом 216 байтов (64Кб) и потомуиспользовали 16-битовые адреса. В последующих моделях память былаувеличена до 220 байтов (1Мб=1000Кб), для чего уже необходимы 20битовые адреса. Однако в этих I80Х86 ради сохраненияпреемственности были сохранены 16-битовые адреса: именно такиеадреса хранятся в регистрах и указываются в командах, именно такиеадреса получаются в результате модификации по базовым и индекснымрегистрам. Как же удается 16-битовыми адресами ссылаться на 1Мбпамяти, и большие объемы?Эта проблема решается с помощью сегментирования адресов(неявного базирования адресов). В I80Х86 вводится понятие "сегментпамяти".
Так называется любой участок памяти размером до 64Кб и сначальным адресом, кратным 16. Абсолютный (20-битовый) адрес Aлюбой ячейки памяти можно представить как сумму 20-битовогоначального адреса (базы) B сегмента, которому принадлежит ячейка, и16-битового смещения D - адреса этой ячейки, отсчитанного от началасегмента: A=B+D. (Неоднозначность выбора сегмента не играетсущественной роли, главное - чтобы сумма B и D давала нужныйадрес.) Адрес B заносится в некоторый регистр S, а в команде, гдедолжен быть указан адрес A, вместо него записывается пара изрегистра S и смещения D (в MASM такая пара, называемая адреснойпарой или указателем, записывается как S:D).
Процессор же устроентак, что при выполнении команды он прежде всего по паре S:Dвычисляет абсолютный адрес A как сумму содержимого регистра S исмещения D и только затем обращается к памяти по этому адресу A.Вот так, заменяя в командах абсолютные адреса на адресные пары, иудается адресовать всю память 16-битовыми адресами (смещениями).В качестве регистра S разрешается использовать не любойрегистр, а только один из 4 регистров, называемых сегментными: CS,DS, SS и ES.
В связи с этим одновременно можно работать с 4сегментами памяти: начало одного из них загружается в регистр CS ивсе ссылки на ячейки этого сегмента указываются в виде пар CS:D,476начало другого заносится в DS и все ссылки на его ячейки задаются ввиде пар DS:D и т.д. Если одновременно надо работать с большимчислом сегментов, тогда нужно своевременно сохранять содержимоесегментных регистров и записывать в них начальные адреса пятого,шестого и т.д. сегментов.Отметим, что используемые сегменты могут быть расположены впамяти произвольным образом: они могут не пересекаться, а могутпересекаться и даже совпадать.
Какие сегменты памяти использовать, вкаких сегментных регистрах хранить их начальные адреса - все этоличное дело автора машинной программы.Как и все регистры I80Х86, сегментные регистры имеют размерслова. Поэтому возникает вопрос: как удается разместить в них 20битовые начальные адреса сегментов памяти? Ответ такой. Посколькувсе эти адреса кратны 16 (см. выше), то в них младшие 4 бита(последняя 16-ричная цифра) всегда нулевые, а потому эти биты можноне хранить явно, а лишь подразумевать. Именно так и делается: всегментном регистре всегда хранятся только первые 16 битов (первыечетыре 16-ричные цифры) начального адреса сегмента (эта величинаназывается номером сегмента или просто сегментом). При вычисленииже абсолютного адреса A по паре S:D процессор сначала приписываетсправа к содержимому регистра S четыре нулевых бита (другимисловами, умножает на 16) и лишь затем прибавляет смещение D, причемсуммирование ведется по модулю 220:Aабс = 16*[S]+D (mod 220)Если, например, в регистре CS хранится величина 1234h, тогдаадресная пара 1234h:507h определяет абсолютный адрес, равный16*1234h+507h = 12340h+507h = 12847h.Сегментные регистры по умолчанию.
Согласно описанной схемесегментирования адресов, замену абсолютных адресов на адресные парынадо производить во всех командах, имеющих операнд-адрес. Однакобыл разработан способ, позволяющий избежать выписывания таких парв большинстве команд. Суть его в том, что устанавливается поумолчанию, какой сегментный регистр на какой сегмент памяти будетуказывать, и что в командах задается только смещение: не указанныйявно сегментный регистр автоматически восстанавливается согласноэтой договоренности. И только при необходимости нарушить этудоговоренность надо полностью указывать адресную пару. Списокумолчаний приводится в таблице.477РегистрУмолчанияCSуказывает на начало областипамяти, в которой размещеныкомандыпрограммы(этаобласть называется сегментомкоманд или сегментом кодов),и потому при ссылках наячейки этой области регистрCS можно не указывать явно,онподразумеваетсяпоумолчаниюDSуказывает на сегмент данных(областьпамятисконстантами, переменными идругимивеличинамипрограммы)SSуказывает на стек - областьпамяти,доступ к которойосуществляется по принципу"последним записан первымсчитан"ESсчитается свободным, он непривязанниккакомусегменту памяти и его можноиспользоватьпосвоемуусмотрениюКомментарийАбсолютный адрес очереднойкоманды,подлежащейвыполнению, всегда задаетсяпарой CS:IP:в счетчикекоманд IP всегда находитсясмещениеэтойкомандыотносительноадресаизрегистра CS.Во всех ссылках на этотсегмент регистр DS можноявно не указывать, т.к.
онподразумеваетсяпоумолчанию.Все ссылки на стек, в которыхявно не указан сегментныйрегистр,поумолчаниюсегментируются по региструSS.Чаще всего он применяетсядля доступа к данным,которые не поместились илисознательнонебылиразмещенывсегментеданных.С учетом такого распределения ролей сегментных регистровмашинные программы обычно строятся так: все команды программыразмещаются в одном сегменте памяти, начало которого заносится врегистр CS, а все данные размещаются в другом сегменте, началокоторого заносится в регистр DS; если нужен стек, то под негоотводится третий сегмент памяти, начало которого записывается врегистр SS. После этого практически во всех командах можно указыватьне полные адресные пары, а лишь смещения, т.к.
сегментные регистрыв этих парах будут восстанавливаться автоматически.Здесь, правда, возникает такой вопрос: как по смещениюопределить, на какой сегмент памяти оно указывает? Точный ответприведен ниже, а в общих чертах он такой: ссылки на сегмент командмогут быть только в командах перехода, а ссылки практически во всехдругих командах (кроме строковых и стековых) - это ссылки на сегментданных. Например, в команде пересылкиMOV AX,X478имя X воспринимается как ссылка на данное, а потому автоматическивосстанавливается до адресной пары DS:X. В команде же безусловногоперехода по адресу, находящемуся в регистре BX,JMP BXабсолютный адрес перехода определяется парой CS:[BX].Итак, если в ссылке на какую-то ячейку памяти не указан явносегментный регистр, то этот регистр берется по умолчанию. Явно жесегментные регистры надо указывать, только если по каким-топричинам регистр по умолчанию не подходит.
Если, например, вкоманде пересылки нам надо сослаться на стек (скажем, надо записать врегистр AH байт стека, помеченный именем X), тогда нас уже не будетустраивать договоренность о том, что по умолчанию операнд командыMOV сегментируется по регистру DS, и потому мы обязаны явноуказать иной регистр - в нашем случае регистр SS, т.к. именно онуказывает на стек:MOV AH,SS:XОднако такие случаи встречаются редко и потому в командах, какправило, указываются только смещения.Отметим, что в MASM сегментный регистр записывается в самойкоманде непосредственно перед смещением (именем переменной,меткой и т.п.), однако на уровне машинного языка ситуация несколькоиная. Имеется 4 специальные однобайтовые команды, называемыепрефиксами замены сегмента (обозначаемые как CS:, DS:, SS: и ES:).Они ставятся перед командой, операнд-адрес которой должен бытьпросегментированпо регистру, отличному от регистра,подразумеваемому по умолчанию.
Например, приведенная вышесимволическая команда пересылки - это на самом деле две машинныекоманды:SS:MOV AH,XСегментирование, базирование и индексирование адресовПоскольку сегментирование адресов- это разновидностьмодификации адресов, то в I80Х86 адрес, указываемый в команде, вобщем случае модифицируется по трех регистрам - сегментному,базовому и индексному. В целом, модификация адреса производится вдва этапа. Сначала учитываются только базовый и индексный регистры(если они, конечно, указаны в команде), причем вычисление здесьпроисходит в области 16-битовых адресов; полученный в результате16-битовый адрес называется исполнительным (эффективным) адресом.Если в команде не предусмотрено обращение к памяти (например, оназагружает адрес в регистр), то на этом модификация адресазаканчивается и используется именно исполнительный адрес (онзагружается в регистр).
Если же нужен доступ к памяти, тогда на479втором этапе исполнительный адрес рассматривается как смещение и кнему прибавляется (умноженное на 16) содержимое сегментногорегистра, указанного явно или взятого по умолчанию, в результате чегополучается абсолютный (физический) 20-битовый адрес, по которомуреально и происходит обращение к памяти.Отметим,что сегментный регистручитывается только в"последний" момент, непосредственно перед обращением к памяти, а доэтого работа ведется только с 16-битовыми адресами. Если учесть ктому же, что сегментные регистры, как правило, не указываются вкомандах, то можно в общем-то считать, что I80Х86 работает с 16битовыми адресами.Как уже сказано, если в ссылке на ячейку памяти не указансегментный регистр, то он определяется по умолчанию.
Это делается последующим правилам.1) В командах перехода адрес перехода сегментируется порегистру CS и только по нему, т.к. абсолютный адрес команды,которая должна быть выполнена следующей, всегда определяется паройCS:IP (попытка изменить в таких командах сегментный регистр будетбезуспешной).Отметим, что сегментирование по регистру CS касается именноадреса перехода, а не адреса той ячейки, где он может находиться.Например, в команде безусловного перехода по адресу, находящемуся вячейке X:JMP Xимя X сегментируется по регистру DS, а вот адрес перехода,взятый из ячейки X, уже сегментируется по регистру CS.2) Адреса во всех других командах, кроме строковых (STOS,MOVS, SCAS и CMPS), по умолчанию сегментируются:- по регистру DS,еслисреди указанных регистровмодификаторов нет регистра BP;- по регистру SS, если один из модификаторов - регистр BP.Таким образом, адреса вида A, A[BX], A[SI], A[DI], A[BX][SI] иA[BX][DI] сегментируются по регистру DS, а адреса A[BP], A[BP][SI] иA[BP][DI] - по регистру SS, т.е.